2

使用集合时的常见模式如下:

number_list = [1,5,7,2,4,4,1,3,8,5]
number_set = set()

for number in number_list:

   #we only want to process the number if we haven't already processed it
   if(number not in number_set):
       number_set.add(number)

       #do processing of 'number' here now that we know it's not a duplicate

这些行让我很烦if(number not in number_set):number_set.add(number)因为我们在这里进行了两次哈希查找,而实际上我们应该只需要一个。

字典有“setdefault”操作,解决了一个非常类似的问题:“如果字典中存在key,则返回值,否则插入这个默认值,然后返回默认值”。如果您天真地执行此操作,IE 以下,您执行两次哈希查找,但 setdefault 允许您一次完成

if item_key in dict:
   dict[item_key].append(item_value)
else:
   dict[item_key] = [item_value]

集合是否有等效的操作?类似的东西,if(number_set.check_if_contains_and_then_add(number)):但给了一个更好的名字。

4

4 回答 4

2

如果分析器告诉您哈希查找贡献了重要的运行时间,那么这可能会解决它。

def add_value(container, value):
    oldlen = len(container)
    container.add(value)
    return len(container) != oldlen

if add_value(number_set, number):
    # process number

但为什么会这样呢?也许是由于__hash__方法缓慢,尽管我现在可以告诉您(a)散列整数并不慢,并且(b)如果可能的话,最好将具有慢速__hash__缓存的类作为结果,而不是减少来电。或者可能是由于速度较慢__eq__,这更难处理。最后,如果内部查找机制本身很慢,那么您可能无法做很多事情来加速您的程序,因为运行时一直在进行哈希查找,在范围内查找名称。

返回一个指示集合是否更改的值可能会很好set.add,但我认为这个想法违背了 Python 库的原则(诚然不是普遍支持的),即变异操作不会返回值,除非它是基本的到操作这样做。所以函数当然会返回pop()一个值,但即使它偶尔对用户有用也会返回。list.sort()Noneself

我想你可以这样做:

def deduped(iterable):
    seen = set()
    count = 0
    for value in iterable:
        seen.add(value)
        if count != len(seen):
            count += 1
            yield value

for number in deduped(number_list):
    # process number

当然,重复的哈希查找是任何类型的问题纯粹是猜测:我通常会if not in像在原始代码中那样编写带有测试的任何一个函数,并且该函数的目的是简化调用代码,而不是避免多余的哈希查找。

于 2013-10-27T21:54:14.057 回答
2

不,那里没有。

setdefault方法用于设置字典中键的默认,集合没有值,因此完全没有意义。

如果订单无关紧要,请尝试此操作。

number_list = [1,5,7,2,4,4,1,3,8,5]
number_set = set(number_list)

for number in number_set:
   #do processing of 'number' here now that we know it's not a duplicate
于 2013-10-27T19:49:59.227 回答
0

你为什么不做number_set.add(number)呢?setdefault 的要点是它不会覆盖键的现有值(如果存在)。但是一个集合没有值,只有一个键,所以覆盖是无关紧要的。

于 2013-10-27T19:51:00.803 回答
0

不,没有setdefault类型方法sets,但您可以执行以下操作:

number_list = [1,5,7,2,4,4,1,3,8,5]
number_set = set()

for number in number_list:
   if number not in number_set and not number_set.add(number):
       #do somethihng here

仅当isnot number_set.add(number)时才会调用条件。number not in number_setTrue

使用它,您可以以有序的方式处理独特的项目(保持顺序)。

>>> number_list = [1,5,7,2,4,4,1,3,8,5]
>>> seen = set()
>>> [x for x in number_list if x not in seen and not seen.add(x)]
[1, 5, 7, 2, 4, 3, 8]

如果订单无关紧要,那么只需set()调用number_list

>>> set(number_list)
{1, 2, 3, 4, 5, 7, 8}
于 2013-10-27T19:54:57.043 回答