python是否提供了一种检查不同类型序列“相等”的优雅方法?以下工作,但对于python代码来说它们看起来相当丑陋和冗长:
def comp1(a, b):
if len(a) != len(b):
return False
for i, v in enumerate(a):
if v != b[i]:
return False
return True
以下内容有点短,但由于创建了第三个序列,效率也会降低:
def comp2(a, b):
for l, r in map(None, a, b):
if l != r:
return False
return True
将其中一个例子写入列表理解并不是我正在寻找的。 p>
编辑:理想情况下,我正在寻找一种在比较期间不会创建另一个序列的解决方案。
答案 0 :(得分:17)
将两个序列转换为列表,并使用内置列表比较。它应该足够了,除非你的序列非常大。
list(a) == list(b)
编辑:
schickb完成的测试显示使用元组稍快一些:
tuple(a) == tuple(b)
答案 1 :(得分:12)
您可以使用以下内容确定任何两个迭代(字符串,元组,列表,甚至自定义序列)的相等性,而无需创建和存储重复列表:
all(x == y for x, y in itertools.izip_longest(a, b))
请注意,如果两个迭代的长度不同,则较短的一个将填充None
s。换句话说,它会将[1, 2, None]
视为等于(1, 2)
。
编辑:正如卡米尔在评论中指出的那样,izip_longest
仅适用于Python 2.6。但是,the docs for the function还提供了一个替代实现,它应该一直工作到2.3。
编辑2:在几台不同的计算机上进行测试后,在某些情况下,这似乎只比list(a) == list(b)
更快,我无法隔离。大多数情况下,它需要大约七倍的时间。但是,我还发现tuple(a) == tuple(b)
始终至少是list
版本的两倍。
答案 2 :(得分:5)
除了创建临时列表/元组所使用的额外内存之外,当序列中早期出现不等式时,这些答案将会丢失为大序列的短路生成器解决方案
from itertools import starmap, izip
from operator import eq
all(starmap(eq, izip(x, y)))
或更简洁
from itertools import imap
from operator import eq
all(imap(eq, x, y))
来自ipython的一些基准
x=range(1000)
y=range(1000); y[10]=0
timeit tuple(x) == tuple(y)
100000 loops, best of 3: 16.9 us per loop
timeit all(imap(eq, x, y))
100000 loops, best of 3: 2.86 us per loop
答案 3 :(得分:2)
看起来像元组(a)==元组(b)是最好的整体选择。或者也许与前面的len检查进行元组比较,如果它们通常是不同的长度。这确实创建了额外的列表,但希望不是一个问题,除了真正庞大的列表。以下是我对各种替代方案的比较:
import timeit
tests = (
'''
a=b=[5]*100
''',
'''
a=[5]*100
b=[5]*3
''',
'''
a=b=(5,)*100
''',
'''
a=b="This on is a string" * 5
''',
'''
import array
a=b=array.array('B', "This on is a string" * 5)
'''
)
common = '''import itertools
def comp1(a, b):
if len(a) != len(b):
return False
for i, v in enumerate(a):
if v != b[i]:
return False
return True'''
for i, setup in enumerate(tests):
t1 = timeit.Timer("comp1(a, b)", setup + common)
t2 = timeit.Timer("all(x == y for x, y in itertools.izip_longest(a, b))", setup + common)
t3 = timeit.Timer("all([x == y for x, y in itertools.izip_longest(a, b)])", setup + common)
t4 = timeit.Timer("list(a) == list(b)", setup + common)
t5 = timeit.Timer("tuple(a) == tuple(b)", setup + common)
print '==test %d==' % i
print ' comp1: %g' % t1.timeit()
print ' all gen: %g' % t2.timeit()
print 'all list: %g' % t3.timeit()
print ' list: %g' % t4.timeit()
print ' tuple: %g\n' % t5.timeit()
结果如下:
==test 0==
comp1: 27.8089
all gen: 31.1406
all list: 29.4887
list: 3.58438
tuple: 3.25859
==test 1==
comp1: 0.833313
all gen: 3.8026
all list: 33.5288
list: 1.90453
tuple: 1.74985
==test 2==
comp1: 30.606
all gen: 31.4755
all list: 29.5637
list: 3.56635
tuple: 1.60032
==test 3==
comp1: 33.3725
all gen: 35.3699
all list: 34.2619
list: 10.2443
tuple: 10.1124
==test 4==
comp1: 31.7014
all gen: 32.0051
all list: 31.0664
list: 8.35031
tuple: 8.16301
修改:添加了一些测试。这是在带有2GB内存的AMD 939 3800+上运行的。 Linux 32bit,Python 2.6.2
答案 4 :(得分:1)
由于您在引号中加上“相等”一词,我假设您想知道列表是如何相同以及它们是如何不同的。查看具有SequenceMatcher类的 difflib :
sm = difflib.SequenceMatcher(None, a, b)
for opcode in sm.get_opcodes():
print " (%s %d:%d %d:%d)" % opcode
您将获得一系列差异的描述。将其转换为 diff 类似的输出相当简单。
答案 5 :(得分:0)
它可能效率不高,但看起来很时髦:
def cmpLists(a, b):
return len(a) == len(b) and (False not in [a[i] == b[i] for i in range(0,len(a)])
我不知道Ben mentioned的“全部”功能,但也许您可以使用它而不是“假而不是”
答案 6 :(得分:0)
这个“功能”代码应该足够快速和通用,适用于所有目的。
# python 2.6 ≤ x < 3.0
import operator, itertools as it
def seq_cmp(seqa, seqb):
return all(it.starmap(operator.eq, it.izip_longest(seqa, seqb)))
如果在Python 2.5上,请使用there中的izip_longest定义。
答案 7 :(得分:0)
我认为当两个序列都是list
类型时,特殊情况是个好主意。比较两个列表比将两个列表都转换为元组更快(并且内存效率更高)。
如果a
或b
不是列表,则它们都会转换为tuple
。如果一个或两个都已经是元组,则没有开销,因为在这种情况下tuple()
只返回对原始对象的引用。
def comp(a, b):
if len(a) != len(b):
return False
if type(a) == type(b) == list:
return a == b
a = tuple(a)
b = tuple(b)
return a == b