【问题标题】:One liner to determine if dictionary values are all empty lists or not一个确定字典值是否都是空列表的衬垫
【发布时间】:2011-05-04 20:42:32
【问题描述】:

我的字典如下:

someDict = {'a':[], 'b':[]}

我想确定这本字典是否有任何非空列表的值。如果是这样,我想返回 True。如果没有,我想返回 False。有什么方法可以使它成为一个衬里吗?

【问题讨论】:

  • 嗯,我们在这里被困在 Python 2.4.1 上,所以 'any' 不起作用,但是下面有很多解决方案可以工作。

标签: python


【解决方案1】:

根据我的测试,以下单行(我的原始答案)在所有情况下都具有最佳时间性能。有关测试信息,请参阅下面的编辑。我确实承认使用生成器表达式的解决方案将更加节省内存,并且应该是大型字典的首选。

编辑:这是一个老化的答案,我的测试结果可能对最新版本的 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

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

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

all(map(lambda x: x == [], my_dict.values())):

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



再次编辑 - 更有趣:

any() 是 O(1) 的最佳情况(如果 bool(list[0]) 返回 True)。 any() 最坏的情况是“积极”的情况 - bool(list[i]) 返回 False 的一长串值。


看看当 dict 变大时会发生什么:

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



但这还不够 - 最坏的“错误”情况呢?

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

【讨论】:

  • 谢谢,这是一个有趣的练习!
【解决方案2】:

非虚假或非空列表:

不假:

any(someDict.values())

非空列表:

any(a != [] for a in someDict.values())

any(map(lambda x: x != [], someDict.values()))

或者,如果您可以接受错误的返回值:

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

返回一个非空列表的项目列表,因此如果它们都是空列表,则它是一个空列表:)

【讨论】:

    【解决方案3】:

    字面意思:

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

    【讨论】:

      【解决方案4】:

      试试这个

       all([d[i] == [] for i in d])
      

      编辑:哎呀,我想我让你倒退了。让deMorgan那

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

      无论如何,第二种方式比第一种方式具有短路优势

      【讨论】:

      • all() 在第一次出现 False 表达式时也会短路。
      • “deMorgan 那个”?说得好。 :P
      【解决方案5】:
      >>> someDict = {'a':[], 'b':[]} 
      >>> all(map(lambda x: x == [], someDict.values()))
      True
      

      【讨论】:

      • 偏好列表理解优于地图,尤其是带 lambda -- stackoverflow.com/questions/1247486/…
      • @Ben: s/list comprehension/generator expression/.
      • @delnan 不符合我在答案中发布的结果。想详细说明这一立场吗?
      • 对于 99.9999% 的情况,在这里担心性能是荒谬的。我发现地图语法是最易读的,但回想起来,列表理解可能是做到这一点的“标准”方式。
      • 不管任何微小的速度差异(无论如何版本之间都会有所不同),生成器版本在空间上是 O(1)(它一次只计算一个项目)并且可能具有比线性的,因为它从不计算超出必要的项目,即一旦遇到空列表,它就会短路(尝试使用字典 dict(('a'*i, [i]) for i in range(10000)) 进行基准测试)。您还保存了两个括号;)
      【解决方案6】:
      len(filter(lambda x: x!=[], someDict.values())) != 0
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2014-07-19
        • 2022-10-04
        • 1970-01-01
        • 1970-01-01
        • 2023-01-29
        • 1970-01-01
        • 2017-07-05
        • 2022-06-22
        相关资源
        最近更新 更多