合并两个字符串列表

时间:2013-12-10 07:51:42

标签: python string list

给定两个包含重复项的字符串列表,保存每个列表中的一个元素,如何将两者合并为一个列表,其中包含列表顺序中每个值的一个副本?

例如,给出Python中的以下两个列表:

a = ['Second', 'Third', 'Fourth']
b = ['First', 'Second', 'Third']

或者

a = ['First', 'Third', 'Fourth']
b = ['First', 'Second', 'Third']

如何将两个列表合并为一个列表,如下所示:

result = ['First', 'Second', 'Third', 'Fourth']

请注意,不一定要信任字符串的确切值以帮助对元素进行排序。

我知道有可能会出现一些没有明确方法将列表锁定到特定订单的情况,并且可能需要特殊情况,但对于一般情况我宁愿拥有程序要遵循。例如:

a = ['First', 'Third', 'Fourth']
b = ['First', 'Second', 'Fourth']

这可以按任意顺序排列'Third''Second',因为它们之间的两个列表中都没有项目来提供指南。

编辑:我应该进一步解释这些字符串,因为我看到很多人都认为我只能对这两个列表进行原始合并,而这只是不起作用。

我正在拍故事片,对于每个故事,只列出其他分期而不是链接故事本身。因此,通过获取两个列表(或者可能更多,我不确定),我可以提供完整的分期列表,以便按正确顺序排列。

7 个答案:

答案 0 :(得分:4)

简单的algorythm:

  1. Concat列表
  2. 删除重复
  3. 排序
  4. 代码:

    def order_list(lst, order_dict):
         return sorted(list(lst), key = lambda x: order_dict.get(x, -1))
    
    c = list(set(a + b))
    ord_dict = {"First": 1, "Second": 2, "Third": 3, "Fourth": 4}
    order_list(c, ord_dict)
    

答案 1 :(得分:4)

您有两个不同的顾虑:

  • 重复删除
  • 排序

我会分开做。复制消除很简单。使用set

>>> a = ['Second', 'Third', 'Fourth']
>>> b = ['First', 'Second', 'Third']
>>> x = set(a)
>>> x
set(['Second', 'Fourth', 'Third'])
>>> x.update(b)
>>> x
set(['Second', 'Fourth', 'Third', 'First'])

然后你需要以某种方式定义排序。最简单的方法可能是将每个可能的元素映射到一个值:

>>> order_dict = {'First': 1, 'Second': 2, 'Third': 3, 'Fourth': 4}
>>> result = sorted(list(x), key=lambda i: order_dict[i])
>>> result
['First', 'Second', 'Third', 'Fourth']

或者,您可以使用某种比较函数与sorted的{​​{1}}参数,如果您可以为您的值定义一个。

希望这有帮助。

答案 2 :(得分:2)

如果我们假设你的两个列表都是有序的,并且它们每个都只缺少整个集合中的一些元素,那么我可以看到一个算法应该大部分时间

  1. 获取A中的下一个索引。
  2. 逐步找B匹配:
    1. 如果匹配:
      • 删除从B开头到B包括匹配的所有内容,然后添加到C
    2. 如果没有匹配:
      • 将索引A添加到C
  3. 重复
  4. 如果B中还有任何内容,请将其添加到C。
  5. 这是算法的python代码:

    a1 = ['Second', 'Third', 'Fourth']
    b1 = ['First', 'Second', 'Third']
    
    a2 = ['First', 'Third', 'Fourth']
    b2 = ['First', 'Second', 'Third']
    
    a3 = ['First', 'Third', 'Fourth']
    b3 = ['First', 'Second', 'Fourth']
    
    def merge(a, b):
        c = []
        b_oldindex = 0
        for a_index in range(len(a)):
            match = False
            for b_index in range(b_oldindex, len(b)):
                if a[a_index] == b[b_index]:
                    c.extend(b[b_oldindex:b_index+1])
                    b_oldindex = b_index + 1
                    match = True
                    break
            if not match:
                c.append(a[a_index])
        if b_oldindex < len(b):
            c.extend(b[b_oldindex:])
        return c
    
    print(merge(a1,b1))
    print(merge(a2,b2))
    print(merge(a3,b3))
    print(merge(b1,a1))
    print(merge(b2,a2))
    print(merge(b3,a3))
    

    产生以下输出:

    ['First', 'Second', 'Third', 'Fourth']
    ['First', 'Second', 'Third', 'Fourth']
    ['First', 'Third', 'Second', 'Fourth']
    ['First', 'Second', 'Third', 'Fourth']
    ['First', 'Second', 'Third', 'Fourth']
    ['First', 'Second', 'Third', 'Fourth']
    

    在所有测试用例中,唯一未能产生正确顺序的是merge(a3,b3)

    完全解决问题可能涉及实施正确的合并算法(如合并排序中所使用的),这需要能够评估元素应该在的顺序。您可以在Rosetta代码中看到python implementation of merge sort

    <强>更新

    鉴于这实际上是对一组书中的分期付款进行排序,您可以通过考虑其他信息来避免在第三组数据中描述的情况。即,使用版权或发布日期的反向顺序列表中的merge功能。

    例如,在您的情况下:

    a3 = ['First', 'Third', 'Fourth']  # Second novel
    b3 = ['First', 'Second', 'Fourth'] # Third novel
    

    a3的书将在b3的书之前出版。如果您可以收集这种元数据,那么您可以避免这个问题。

    版权日期在同一本书的不同版本之间不会有所不同,但发布日期可能会有所不同。因此,我会在发布日期之前查看版权日期。

答案 3 :(得分:1)

set容器的定义是没有重复项。您可以创建一组两个列表,然后将其强制转换为列表类型:

a = ['Second', 'Third', 'Fourth']
b = ['First', 'Second', 'Third']
c= list(set(a+b))
['Second', 'Fourth', 'Third', 'First']
#Note that set will not organize anything, it will just delete the duplicates

答案 4 :(得分:1)

我有同样的问题,我有一个答案。我发现这篇文章是因为我正在寻找更多的pythonic方法。

首先,关于特殊情况的说明:

a=['A','C','D','E']
b=['A','B','D','F']
c=joinListsOrdered(a,b)

就我而言,我没有任何问题:['A','B','C','D','E','F']['A','C','B','D','F','E']一样好。我想要的唯一验证条件是:c中元素的顺序分别与ab中的顺序相对应,即[el for el in c if el in a]在元素方面等于{{1} (等同于a)。我还认为,如果没有关于这个问题的进一步信息,这是对这个问题唯一合理的立场。

这转化为:重点是关于共同元素(b)。如果那些是正确的顺序,其他一切,可以很容易地卡在中间。因此,这个算法:

['A', 'D']

当然,如果某个公共元素的def joinListsOrdered(a,b): # Find ORDERED common elements order={} for i, e in enumerate(a): order[e]=i commonElements=sorted(set(a) & set(b), key=lambda i: order[i]) # Cycle on each common element. i=0 #index of a j=0 #index of b c=[] for comEl in commonElements: while not a[i]==comEl: c.append(a[i]) i=i+1 while not b[j]==comEl: c.append(b[j]) j=j+1 c.append(comEl) i=i+1;j=j+1 # Add the eventual residuals after the last common element. c=c+a[i:]+b[j:] return c a中的顺序不同,则无法遵守验证条件,但在这种情况下,问题没有解决方案。

答案 5 :(得分:0)

在最简单的情况下,只有一个元素是不同的,并且它位于相同的位置,只是通过两个字符串连接迭代

newlist = []
for i in range(len(a)):
  if a[i] == b[i]:
    newlist.append(a)
  else:
    newlist.append(a)
    newlist.append(b)

如果您的列表更复杂,请先将其中一个列入字典,然后在合并时检查另一个字典。

答案 6 :(得分:-1)

使用Python的bisect库。

from bisect import insort

a = ['First', 'Third', 'Fourth']
b = ['First', 'Second', 'Fourth']
for entry in b:
    insort(entry, a)

unique = Set(a)
print unique

注意:显然,字符串不能正确比较,你可能想要使用字典!