使用集合时的常见模式如下:
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”操作,它解决了一个非常类似的问题:“如果字典中存在键,则返回值,否则插入此默认值,然后返回默认值”。如果您天真地执行此操作,即以下内容,您将执行两次哈希查找,但 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)):
,但有一个更好听的名字。
如果探查器告诉您哈希查找会消耗大量运行时间,那么这可能会解决它。
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()
返回 None
,即使它返回 self
有时会对用户有用。
我想你可以做这样的事情:
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
测试编写这些函数中的任何一个,并且该函数的目的是简化调用代码,不是为了避免多余的哈希查找。
不,没有。
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
你为什么不直接做
number_set.add(number)
呢? setdefault 的要点是它不会覆盖键的现有值(如果存在)。但是集合没有值,只有键,所以覆盖是无关紧要的。
不,
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
仅当
not number_set.add(number)
为 number not in number_set
时才会调用 True
条件。
使用此功能,您可以按顺序处理独特的项目(保留顺序)。
>>> 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}