Python - 检查字典中是否有任何值不是None(无需迭代器)

30

我想知道能否通过这段代码获得相同的输出结果:

d = {'a':None,'b':'12345','c':None}
nones=False
for k,v in d.items(): 
  if d[k] is None:
    nones=True      
或者
any([v==None for v in d.values()])

但是没有for循环迭代器或生成器?


4
在不迭代列表的情况下无法检查其中的值。 - Maroun
1
你需要检查所有的值;循环出了什么问题? - Martijn Pieters
你不需要使用列表推导式。只需使用any(d.values())。但是它会在内部进行循环。无法避免这种情况。 - juanchopanza
罗伯特,看看哈希表是如何工作的(以及它们是什么)。你可能会在那里找到你想要的东西。https://dev59.com/MXRC5IYBdhLWcg3wVvnL - zom-pro
1
为什么这个问题被投票评价得如此之低? - zom-pro
你使用 any() 的版本包含了一个列表推导式,而不是生成器表达式。any() 会短路,所以一旦找到 True 的结果就会停止。这在生成器表达式上很有效,但当你在列表推导式上使用它时,在 any 测试开始之前会创建完整的列表。 - PM 2Ring
2个回答

22

您可以使用

nones = not all(d.values())

如果所有的值都不是None,那么None将被设置为False,否则为True。虽然这只是一个抽象概念,但在内部它必须遍历值列表。


5
这并不是测试 None,而是测试类似 False 的值。 - Jon
@Jon 在大多数鸭子类型的语言中,除非明确需要,在这种情况下并不清楚,否则它不应该这样做。 - hspandher
2
如果字典中包含False,这将会导致程序出错。 - motobói

15

您可以使用字典视图让Python在C代码中进行循环;这将针对所有值执行成员资格测试,而无需创建新列表:

if None not in d.values():

(在Python 2中,使用dict.viewvalues()来获取字典视图,因为dict.values()会返回一个列表)。

Python 3演示:

>>> d = {'a': None, 'c': None, 'b': '12345'}
>>> None not in d.values()
False

这将循环遍历值直到找到匹配项,就像列表成员或适当的any()测试一样,使得这个测试是O(N)的。这与字典或集合成员测试不同,哈希可以用来给你一个平均固定成本测试。

您没有正确使用any()函数; 删除[...]括号:

if any(v is not None for v in d.values()):  # Python 2: use d.itervalues() or d.viewvalues()

如果你的目标是测试多个值,而且你需要避免为每个测试进行不断循环,考虑创建一个反向索引:

inverse_index = {}
for key, value in d.items():
    inverse.setdefault(value, set()).add(key)

这需要这些值可哈希。现在你可以简单地测试每个值:

if None not in inverse_index:

在O(1)时间内。


1
Python 3中的any(map(lambda x: x is not None, d.values()))如何?它更高效,并且在Python 2中也适用。 - Niklas R
@NiklasR: x是Nonelambda调用也有开销,我不确定它是否比其它更高效值得这样做。 - Martijn Pieters
@NiklasR:无论如何,使用字典视图进行成员测试要便宜得多(只需一个方法调用,其他所有内容都在C中处理,具有轻量级对象)。 - Martijn Pieters
1
你可以指出,在检查现有字典的值时,没有避免 O(N) 成本的方法。但是,你可以使用其他数据结构来避免它。例如,如果这些值也是反向字典中的键,那么这将是一个 O(1) 测试。在某些使用场景下,可能需要与原始字典一起构建这个数据结构。 - strubbly
1
@strubbly:这也是个好主意,很可能是OP所说的X到Y问题。 - Martijn Pieters
显示剩余4条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接