Python 如何查找存在于两个列表中但索引不同的元素

Python 如何查找存在于两个列表中但索引不同的元素,python,algorithm,list,language-agnostic,Python,Algorithm,List,Language Agnostic,我有两个相同长度的列表,其中包含各种不同的元素。我试图比较它们,以找到两个列表中存在的元素数量,但索引不同 以下是一些示例输入/输出,以说明我的意思: >>> 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 >>> com

我有两个相同长度的列表,其中包含各种不同的元素。我试图比较它们,以找到两个列表中存在的元素数量,但索引不同

以下是一些示例输入/输出,以说明我的意思:

>>> 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

有没有更简洁、更有说服力的方法来做同样的事情?

因为重复项不算,所以可以使用
set
s只查找每个
列表中的元素。
集合
仅包含唯一的元素。然后使用
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中,您必须首先从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
是一种函数式编程结构,传统上将iterable简化为单个项。这里我们使用
reduce
set
交点减少为单个值

lambda
函数是匿名函数。说出
lambda x,y:x+1
类似于说出
def func(x,y):返回x+y
,只是函数没有名称
reduce
将函数作为其第一个参数。当与
reduce
一起使用时,
lambda
接收的第一个参数a是前一个函数的结果,
累加器

set(l1)&set(l2)
是由
l1
l2
中的唯一元素组成的集合。它被迭代,每个元素一次提取一个,并用作
lambda
函数的第二个参数


0
是累加器的初始值。我们之所以使用此函数,是因为我们假设有0个共享元素以不同的索引开始。

此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)))

我不认为这是最简单的答案,但它只是一句简单的话

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()

比较([1,3],[3,3])的结果是什么?@JuanLopes它将是0,因为两个列表中的最后一个元素将首先被过滤并删除,并且不计数。