我的 dict 包含其键下的列表:
dct = {'a': [1, 2, 3],
'b': [1, 2, 3, 4],
'c': [1, 2]}
识别列表长度是否相同的最佳方式是什么?
这是我的解决方案:
import itertools
len(set(itertools.imap(len, dct.viewvalues()))) == 1
True
如果相似,False
如果不是
UPD:参考@RaymondHettinger建议将map
替换为itertools.imap
答案 0 :(得分:6)
您的解决方案看起来很好。
如果您想稍微调整一下,请使用 itertools.imap()而不是 map()。这会将内存占用减少到O(1)而不是O(n)。
答案 1 :(得分:4)
首先,我会坚持itervalues
,它使用简单的评估。
其次,我会谨慎依赖于使用set
,因为它会在每次遍历字典时执行查找集合中的值。超出时间为O(1)
(如果所有长度相同,则O(n)
更糟糕的情况是O(1)
,如果所有长度都不同则为O(n)
)根据docs。但是很难评估使用set的开销。
在这种情况下,我会使用all
。 all
在找到第一个False
值时失败。因此,长度的第一个不匹配将停止交互过程。但是,如果使用set
,它会通过所有列表到达结尾,然后才将其长度与1
进行比较。
>>> dct = {'a': [1, 2, 3],
'b': [1, 2, 3, 4],
'c': [1, 2]}
>>> lenght_1 = len(dct.itervalues().next())
>>> all(len(value)==lenght_1 for value in dct.itervalues())
False
>>> dct = {'a': [1, 2, 3],
'b': [1, 2, 4],
'c': [1, 2, 5]}
>>> lenght_1 = len(dct.itervalues().next())
>>> all(len(value)==lenght_1 for value in dct.itervalues())
True
可以使用相同的迭代器it
来优化代码,该迭代器不会经过两次第一个值:
>>> it = dct.itervalues()
>>> length_1 = len(next(it))
>>> all(len(value)==l1 for value in it)
True
答案 2 :(得分:2)
注意:ovgolovin's solution要好得多。我在这里留下这个答案,因为有讨论引用它。
您的解决方案很好,但您可以使用生成器表达式,它使用更少的内存并且更具可读性:
len(set(len(x) for x in dct.viewvalues()))) == 1
答案 3 :(得分:1)
正如Michael J. Barber在对the answer的评论中所建议的那样,这是使用groupby
模块中的imap
和itertools的代码。
imap
只会将len
函数应用于每个列表。
groupby
只是以相同长度的块来摸索值。
因此,如果长度不止一个,则长度不同。如果只有一个长度的chuck,这意味着,列表的长度是相同的,第二次访问groupby
迭代器应该产生StopIteration
,从而返回None
(默认next
函数的值。
此代码的好处是imap
和groupby
是用C语言编写的,而且速度非常快。
from itertools import imap,groupby
dct = {'a': [1, 2, 3],
'b': [1, 2, 3, 4],
'c': [1, 2]}
dct2 = {'a': [1, 2, 3],
'b': [1, 2, 34],
'c': [1, 2, 5]}
def check_lenghts(iterable):
it = groupby(imap(len,iterable.itervalues()))
next(it,None)
return True if next(it,None)==None else False
print(check_lenghts(dct))
print(check_lenghts(dct2))