【问题标题】:Common elements between two lists and preserving the order of elements in the two lists两个列表之间的公共元素并保留两个列表中元素的顺序
【发布时间】:2014-01-10 13:38:37
【问题描述】:

我有两个列表 list1 和 list2。我在 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,所以 'e' 在 'a' 之前,因为 2+1

那么,有没有什么简单的方法可以让两个列表之间有共同的元素并保持元素的顺序?

【问题讨论】:

  • 假设 'e' 和 't' 在 list1 中交换,您希望采用什么顺序?
  • list1=['a','b']; list2=['b','a'] 的预期输出是什么?按照您的算法,“a”和“b”都具有相同的位置值3,那么哪个先出现?
  • @Kevin 在这种情况下,结果是 [a, b] 还是 [b, a] 都没有关系

标签: python list


【解决方案1】:

您可以使用列表推导过滤来自list1 的所有不属于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']

虽然这不符合您主要帖子中的预期结果,但从您的后续评论来看,这似乎是可以接受的结果。


您也可以继续使用 set 方法,然后使用您描述的定位算法对结果进行事后排序:

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

【讨论】:

    【解决方案2】:
    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']
    

    【讨论】:

      【解决方案3】:

      您可以像这样保留一个列表的顺序,只需将其中一个设置为一组:

      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']。

      【讨论】:

      • 这会删除单例,但也会删除重复项所在的信息...
      • 已修改...但另一个答案是一样的,但现在有另一个更短的答案。可能很快就会删除。
      【解决方案4】:

      您的订购功能看起来很奇怪,但还可以。您需要找到交集并基本上按您的排序功能对其进行排序。

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2012-12-07
        • 2018-05-07
        • 1970-01-01
        • 2021-01-01
        • 2019-01-17
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多