3

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

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

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

有没有更简洁和雄辩的方式来做同样的事情?

4

3 回答 3

1

由于重复不计算在内,您可以使用sets 仅查找 each 中的元素list。Aset只包含独特的元素。然后只选择两者之间共享的元素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是一个函数式编程结构,传统上将可迭代减少为单个项目。在这里,我们使用reduceset交集减少为单个值。

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 个具有不同索引的共享元素开始。

于 2013-05-13T18:19:33.010 回答
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)))
于 2013-05-13T18:41:19.103 回答
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()

于 2013-05-13T19:26:11.103 回答