如何过滤一组(int,str)元组,只返回第一个元素中带有最小值的元组?

问题描述 投票:3回答:4

假设我有一组表示带有“得分”的URL的元组:

{(0.75, 'http://www.foo.com'), (0.33, 'http://www.bar.com'), (0.5, 'http://www.foo.com'), (0.66, 'http://www.bar.com')}

我有什么简洁的方法来过滤掉重复的URL,只返回得分最低的URL?也就是说,从上面的示例中,我想获得以下集合,其中每个URL仅出现一次,具有来自原始集合的最低对应分数:

{(0.5, 'http://www.foo.com'),(0.33, 'http://www.bar.com')}

我提出了以下解决方案:

from collections import defaultdict

seen = defaultdict(lambda:1)
for score, url in s:
    if score < seen[url]:
        seen[url] = score

filtered = {(v,k) for k,v in seen.items()}

...但我觉得可能有一些更简单,更有效的方法来做到这一点,而不使用中间字典来跟踪最大元素,然后从中重新生成集合。通过第一个元素的最小值/最大值过滤一组元组的最佳方法是什么?

python filter set tuples min
4个回答
3
投票

你已经实现了我能想到的最简单的方法。我所做的唯一改变就是循环 - 一个稍微简洁的版本是使用min

seen = defaultdict(lambda: 1)  # `lambda: float('inf')` if scores can be > 1
for score, url in s:
    seen[url] = min(seen[url], score)

{(v,k) for k,v in seen.items()}
# {(0.33, 'http://www.bar.com'), (0.5, 'http://www.foo.com')}

如果你真的想要一个更短的解决方案,就像我说的那样,这不是最简单的方法,但它是一个单线程。大多数挑战是交换URL和分数,因此您可以在删除重复项时将URL用作密钥。不言而喻,排序是一个先决条件(这就是为什么我不像上面那样喜欢这个解决方案)。

{(v, k) for k, v in dict(sorted(((v, k) for k, v in s), reverse=True)).items()}
# {(0.33, 'http://www.bar.com'), (0.5, 'http://www.foo.com')}

如果s看起来像这样,这个解决方案会变得那么短:

s2 = {(v,k) for k, v in s}
s2 
# {('http://www.bar.com', 0.33), ('http://www.bar.com', 0.66), ...}

你只需要这样做

list(dict(sorted(s2, reverse=True)).items())
# [('http://www.foo.com', 0.5), ('http://www.bar.com', 0.33)]

1
投票

另一种方案:

seen = {}
for score, url in s:
    if seen.setdefault(url, score) > score:
        seen[url] = score
filtered = {(v,k) for k,v in seen.items()}
print(filtered)

1
投票

没有任何技巧或额外的代码可以重复使用,你非常接近。在我看来,我想出了一些类似的东西:

seen = set()
filtered = []
for score, url in sorted(urls):
    if url in seen:
        continue
    filtered.append((score, url))
    seen.add(url)

您还可以使用其他库,例如boltons。您可以像这样使用unique方法:

import operator
from boltons.iterutils import unique
filtered = unique(sorted(urls), key=operator.itemgetter(1))

更新:如果元组将所有相关评分作为第一个元素,则此解决方案适用于任意长度的元组(假设您更改了键功能)


1
投票

一个非常简单的方法:

L=sorted(s,key=lambda t: (t[1],t[0]))
[L[0]] + [L[i] for i in range(1,len(L)) if L[i][1]!=L[i-1][1]]
© www.soinside.com 2019 - 2024. All rights reserved.