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


问题内容

假设我有一组用“分数”表示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()}

…但是我觉得可能有一些更简单,更有效的方法来执行此操作,而无需使用中介指令来跟踪max元素,然后从中重新生成该集合。按第一个元素的最小值/最大值过滤一组元组的最佳方法是什么?


问题答案:

您已经实现了我能想到的最简单的方法。我唯一要进行的更改就是对循环进行修改-正在使用更简洁的版本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)]