我有两个相同长度的列表,其中包含各种不同的元素。我正在尝试比较它们以找到两个列表中存在的元素数量,但它们具有不同的索引。
以下是一些示例输入/输出来说明我的意思:
>>> compare([1, 2, 3, 4], [4, 3, 2, 1])
4
>>> compare([1, 2, 3], [1, 2, 3])
0
# Each item in the first list has the same index in the other
>>> compare([1, 2, 4, 4], [1, 4, 4, 2])
2
# The 3rd '4' in both lists don't count, since they have the same indexes
>>> compare([1, 2, 3, 3], [5, 3, 5, 5])
1
# Duplicates don't count
列表的大小始终相同。
这是我到目前为止的算法:
def compare(list1, list2):
# Eliminate any direct matches
list1 = [a for (a, b) in zip(list1, list2) if a != b]
list2 = [b for (a, b) in zip(list1, list2) if a != b]
out = 0
for possible in list1:
if possible in list2:
index = list2.index(possible)
del list2[index]
out += 1
return out
是否有更简洁,更有说服力的方法来做同样的事情?
答案 0 :(得分:1)
由于重复项不计,您可以使用set
来仅查找每个list
中的元素。 set
仅包含唯一元素。然后使用list.index
def compare(l1, l2):
s1, s2 = set(l1), set(l2)
shared = s1 & s2 # intersection, only the elements in both
return len([e for e in shared if l1.index(e) != l2.index(e)])
如果你想要
,你实际上可以把它变成一个单行def compare(l1, l2):
return len([e for e in set(l1) & set(l2) if l1.index(e) != l2.index(e)])
<强>替代:强>
在功能上你可以使用reduce
内置(在python3中,你必须先from functools import reduce
)。这避免了构建列表,从而节省了过多的内存使用量。它使用lambda函数来完成工作。
def compare(l1, l2):
return reduce(lambda acc, e: acc + int(l1.index(e) != l2.index(e)),
set(l1) & set(l2), 0)
简要说明:
reduce
是一个函数式编程构造,它将传统的迭代减少到单个项目。在这里,我们使用reduce
将set
交集减少为单个值。
lambda
函数是匿名函数。说lambda x, y: x + 1
就像说def func(x, y): return x + y
,除了函数没有名字。 reduce
将函数作为其第一个参数。 lambda
与reduce
一起使用时收到的第一个参数是上一个函数accumulator
的结果。
set(l1) & set(l2)
是由l1
和l2
中的唯一元素组成的集合。它被迭代,每个元素一次取出一个,并用作lambda
函数的第二个参数。
0
是累加器的初始值。我们使用它,因为我们假设有0个具有不同索引的共享元素开始。
答案 1 :(得分:1)
这个python函数适用于您提供的示例:
def compare(list1, list2):
D = {e:i for i, e in enumerate(list1)}
return len(set(e for i, e in enumerate(list2) if D.get(e) not in (None, i)))
答案 2 :(得分:1)
我不是说这是最简单的答案,但它只是一个单行。
import numpy as np
import itertools
l1 = [1, 2, 3, 4]
l2 = [1, 3, 2, 4]
print len(np.unique(list(itertools.chain.from_iterable([[a,b] for a,b in zip(l1,l2) if a!= b]))))
我解释说:
[[a,b] for a,b in zip(l1,l2) if a!= b]
是来自zip(l1,l2)
的不同项目的情侣列表。此列表中的元素数是两个列表中相同位置的项目不同的位置数。
然后,list(itertools.chain.from_iterable()
用于合并列表的组件列表。例如:
>>> list(itertools.chain.from_iterable([[3,2,5],[5,6],[7,5,3,1]]))
[3, 2, 5, 5, 6, 7, 5, 3, 1]
然后,使用np.unique()
丢弃重复项,然后选择len()
。