集合有等效的 `dict.setdefault` 吗?

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

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

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)):
,但有一个更好听的名字。

python dictionary hash set
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()
返回
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
测试编写这些函数中的任何一个,并且该函数的目的是简化调用代码,不是为了避免多余的哈希查找。


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

0
投票

你为什么不直接做

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


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

仅当

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}
© www.soinside.com 2019 - 2024. All rights reserved.