两个列表的共同元素以及保留两个列表中元素的顺序

7
我有两个列表list1list2。我在stackoverflow上找到了一种非常简单的方法来获取这两个列表中的共同元素,方法如下:result = list(set(list1) & set(list2))。不幸的是,这种方法不能保留结果列表中元素的顺序。
例如:
list1 = ['a', 'e', 't', 'b', 'c']
list2 = ['e', 'b', 'a', 'c', 'n', 's']

我希望结果(共同元素)按照顺序为['e','a','b','c']。因为例如,'e'在list1和list2中,并且在list1的位置2和list2的位置1,而'a'在list1和list2中并且在list1的位置1和list2的位置3,所以因为2 + 1 < 1 + 3,所以'e'在'a'之前。

那么,有没有简单的方法来获取两个列表之间的共同元素并保留元素的顺序?


假设在list1中交换了'e'和't',你希望进行什么排序? - wim
“list1=['a','b']; list2=['b','a']” 的预期输出是什么?根据您的算法,'a' 和 'b' 都具有相同的位置值 3,那么哪个先出现呢? - Kevin
@Kevin,在这种情况下,结果是[a,b]还是[b,a]并不重要。 - shn
4个回答

5
你可以使用列表推导式过滤掉所有不属于list2的元素,代码如下:[x for x in list1 if x in list2]
list1 = ['a', 'e', 't', 'b', 'c']
list2 = ['e', 'b', 'a', 'c', 'n', 's']

result = [item for item in list1 if item in list2]
print result

结果:

['a', 'e', 'b', 'c']

虽然这不符合您主帖中所期望的结果,但根据您的后续评论,似乎这是可以接受的结果。
您还可以继续使用集合方法,并在事后使用您描述的定位算法对结果进行排序:
list1 = ['a', 'e', 't', 'b', 'c']
list2 = ['e', 'b', 'a', 'c', 'n', 's']

items = set(list1) & set(list2)
result = sorted(items, key=lambda element: list1.index(element) + list2.index(element))

print result

结果:

['e', 'a', 'b', 'c']

4
list1 = ['a', 'e', 't', 'b', 'c']
list2 = ['e', 'b', 'a', 'c', 'n', 's']

weights = defaultdict(int)

for i, e in enumerate(list1):
   weights[e] += i

for i, e in enumerate(list2):
   weights[e] += i

>>> result = sorted(set(list1) & set(list2), key=lambda i: weights[i])
>>> result
['e', 'a', 'b', 'c']

1
您可以通过将其中一个列表转换为集合来保留一个列表的顺序,方法如下所示:
list1 = ['a', 'e', 't', 'b', 'c']
list2 = ['e', 'b', 'a', 'c', 'n', 's'] 

slist1 = set(list1)
slist2 = set(list2)

# list1 determines the ordering
olist1 = [x for x in list1 if x in slist2]

# list2 determines the ordering
olist2 = [x for x in list2 if x in slist1]

基本上,您要遍历一个列表,并检查每个项是否在另一个列表中。这确保了您的最终列表与原始列表具有相同的顺序,但也仅包括两个列表中都存在的条目。
使用集合可以大大加快包含检查速度。
如果您想做比这更复杂的事情(例如使最终排序依赖于两个列表中的索引),那么您需要更具体地说明这些细节。
编辑:好的,您已经发布了关于您想要做什么的更多详细信息。不知道它是否是最快的,但您可以像这样获取索引:
list1_offsets = dict(x[::-1] for x in enumerate(list1))
list2_offsets = dict(x[::-1] for x in enumerate(list2))

total_list = slist1 & slist2

total_offset = [(x, list1_offsets[x] + list2_offsets[x]) for x in total_list]

final_list = [x[0] for x in sorted(total_offset, key=itemgetter(1))]

在这种情况下,输出结果是预期的 ['e', 'a', 'b', 'c']

这将删除单例,但也会删除重复项的信息... - Tim Pietzcker
修改了...但另一个答案是相同的,只不过现在有一个更短的答案。可能很快就会删除这个答案。 - Corley Brigman

0

你的排序函数看起来有点奇怪,但没关系。基本上,你需要找到交集并按照你的排序函数进行排序。

order_function = lambda val: list1.index(val) + list2.index(val)
common = set(list1) & set(list2)
indexed = [(order_function(v), v) for v in common]
return [x[1] for x in sorted(indexed)]

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接