一句话代码来判断字典值是否全部为空列表

16

我有一个字典,如下所示:

someDict = {'a':[], 'b':[]}
我想确定这个字典是否有任何不是空列表的值。如果有,我想返回True。如果没有,则返回False。有没有办法将其变成一个单行代码?

我想确定这个字典是否有任何不是空列表的值。如果有,我想返回True。如果没有,则返回False。有没有办法将其变成一个单行代码?


哦,我们被困在Python 2.4.1上了,所以“any”不起作用,但下面有很多解决方案可以使用。 - Nathan
6个回答

16

根据我的测试结果,在所有场景下,以下一行代码(即我的原始答案)具有最佳的时间性能。请参见下面的编辑以获取测试信息。我承认,使用生成器表达式的解决方案在内存效率上会更好,并且应该优先考虑用于大型字典。

编辑:这是一个过时的答案,我的测试结果可能不适用于最新版本的Python。由于生成器表达式是更“Pythonic”的方式,我想它们的性能正在改善。如果您在“热”代码路径中运行此代码,请进行自己的测试。

bool([a for a in my_dict.values() if a != []])

编辑:

决定有些乐趣。以下是答案比较,没有特定顺序:

(如下所示,timeit将根据少于0.2秒的运行时间计算循环顺序)

bool([a for a in my_dict.values() if a != []]):

python -mtimeit -s"my_dict={'a':[],'b':[]}" "bool([a for a in my_dict.values() if a != []])"
1000000 loops, best of 3: 0.875 usec per loop

any([my_dict[i] != [] for i in my_dict]) :

python -mtimeit -s"my_dict={'a':[],'b':[]}" "any([my_dict[i] != [] for i in my_dict])"
1000000 loops, best of 3: 0.821 usec per loop

在我的字典中任意一个值不为空列表(x != [])时:

python -mtimeit -s"my_dict={'a':[],'b':[]}" "any(x != [] for x in my_dict.itervalues())"
1000000 loops, best of 3: 1.03 usec per loop

检查my_dict字典的所有值是否为空列表,返回布尔值。

python -mtimeit -s"my_dict={'a':[],'b':[]}" "all(map(lambda x: x == [], my_dict.values()))"
1000000 loops, best of 3: 1.47 usec per loop

filter(lambda x: x != [], my_dict.values()):

python -mtimeit -s"my_dict={'a':[],'b':[]}" "filter(lambda x: x != [], my_dict.values())"
1000000 loops, best of 3: 1.19 usec per loop



再次编辑 - 更有趣:

如果bool(list[0])返回True,any()的最佳情况是O(1)。any()的最坏情况是“正面”场景 - 一个长列表的值,其中bool(list[i])返回False。


看看字典变大时会发生什么:

bool([a for a in my_dict.values() if a != []]) :

#n=1000
python -mtimeit -s"my_dict=dict(zip(range(1000),[[]]*1000))" "bool([a for a in my_dict.values() if a != []])"
10000 loops, best of 3: 126 usec per loop

#n=100000
python -mtimeit -s"my_dict=dict(zip(range(100000),[[]]*100000))" "bool([a for a in my_dict.values() if a != []])"
100 loops, best of 3: 14.2 msec per loop

any([my_dict[i] != [] for i in my_dict]):

#n=1000
python -mtimeit -s"my_dict=dict(zip(range(1000),[[]]*1000))" "any([my_dict[i] != [] for i in my_dict])"
10000 loops, best of 3: 198 usec per loop

#n=100000
python -mtimeit -s"my_dict=dict(zip(range(100000),[[]]*100000))" "any([my_dict[i] != [] for i in my_dict])"
10 loops, best of 3: 21.1 msec per loop



但这还不够-如果是最坏的“False”情况呢?

bool([a for a in my_dict.values() if a != []]) :



python -mtimeit -s"my_dict=dict(zip(range(1000),[0]*1000))" "bool([a for a in my_dict.values() if a != []])"
10000 loops, best of 3: 198 usec per loop

any([my_dict[i] != [] for i in my_dict]) :

python -mtimeit -s"my_dict=dict(zip(range(1000),[0]*1000))" "any([my_dict[i] != [] for i in my_dict])"
1000 loops, best of 3: 265 usec per loop

谢谢,这是一次有趣的练习! - Ben Burns

13

非假值或非空列表:

非假值:

any(someDict.values())

非空列表:

any(a != [] for a in someDict.values())
或者
any(map(lambda x: x != [], someDict.values()))

或者,如果您接受一个假值作为返回值:

filter(lambda x: x != [], someDict.values())
返回一个非空列表的列表,如果它们全部为空列表,则返回空列表 :)

6

确切地说:

any(x != [] for x in someDict.itervalues())

4
尝试这个。
 all([d[i] == [] for i in d])

编辑:糟糕,我想我把你搞反了。让我们对德摩根定理进行转化。

any([d[i] != [] for i in d])

第二种方法在任何情况下都具有比第一种更短的路线优势。


2
all()函数在第一次出现“False”表达式时也会短路。 - Don O'Donnell
"deMorgan that"? 很好的表达。 :P - DJGrandpaJ

2
>>> someDict = {'a':[], 'b':[]} 
>>> all(map(lambda x: x == [], someDict.values()))
True

更倾向于使用列表推导而非map,特别是带lambda函数的情况-- https://dev59.com/mHM_5IYBdhLWcg3wvV5w#1247490 - Ben Burns
@Ben: 将列表解析替换为生成器表达式 - user395760
根据我在答案中发布的结果,与@delnan的说法不符。您能详细说明一下吗? - Ben Burns
对于99.9999%的情况,担心性能是可笑的。我发现map语法最易读,但回想起来,列表推导可能是执行此操作的“标准”方式。 - bnaul
1
无论有任何微小的速度差异(这些差异在版本之间也会有所不同),生成器版本在空间上是O(1)的(它一次只计算一个项目),并且具有比线性更好的时间复杂度,因为它永远不会计算比必要更多的项目,即当遇到空列表时,它将立即短路(请尝试使用字典dict(('a'*i, [i]) for i in range(10000))进行基准测试)。你还可以省下两个括号 ;) - user395760
我希望这不会让我看起来像个巨魔,但Guido在前几天表达了他的观点。请参见他对Michael Foord的评论:https://plus.google.com/u/0/115212051037621986145/posts/HajXHPGN752 - Ben Burns

2
len(filter(lambda x: x!=[], someDict.values())) != 0

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