簡體   English   中英

合並兩個字符串列表

[英]Combine two lists of strings

給定兩個包含重復項的字符串列表,每個列表中都保存一個元素,您如何將二者組合成一個列表,每個列表按列表順序包含每個值的一個副本?

例如,給定以下兩個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' ,因為它們之間的兩個列表中都沒有提供指導的項目。

編輯:我應該進一步解釋字符串,因為我看到你們中的許多人都假設我只能對兩個列表進行原始合並排序,而這行不通。

我正在使用故事標題,對於每個故事,它們僅列出其他部分,而不列出鏈接的故事本身。 因此,通過列出兩個列表(我不確定,可能還有更多),我可以拿出完整的分期付款清單,以按適當順序排列它們。

簡單算法:

  1. Concat列表
  2. 刪除公仔
  3. 分類

碼:

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)

您在這里有2個不同的問題:

  • 重復消除
  • 定購

我會分開做。 消除重復非常簡單。 使用一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']

另外,如果可以為值定義一個比較功能,則可以對sortedcmp參數使用某種比較功能。

希望這可以幫助。

如果我們假設您的兩個列表都是有序的,並且它們每個都只缺少整個集合中的某些元素,那么我可以看到一種算法在大多數情況下都可以使用

  1. 取A中的下一個索引。
  2. 逐步通過B尋找匹配項:
    1. 如果有匹配項:
      • 從B的開頭直到B中的所有匹配項都刪除,然后添加到C中
    2. 如果沒有匹配項:
      • 將索引A添加到C
  3. 重復
  4. 如果B中還有剩余內容,請將其添加到C中。

這是該算法的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)

徹底解決問題可能涉及實現正確的合並算法 (如merge sort中所用 ),該算法需要能夠評估元素應處於的順序。您可以在Rosetta代碼上看到python的實現

更新:

鑒於這實際上是對一組書籍中的分期付款進行排序,因此可以通過考慮其他信息來避免在第三組數據中描述的情況。 即,以與版權或發布日期相反的順序在列表上使用merge功能。

例如,在您的情況下:

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

a3的書本應該早於b3的書出版。 如果可以收集這種元數據,則可以避免此問題。

同一本書的不同版本之間的版權日期不會有所不同,但出版日期可能會有所不同。 因此,我將在出版日期之前查看版權日期。

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

我有同樣的問題,我也有答案。 我找到了這篇文章,是因為我正在尋找更多的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]在元素方面等於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

當然,如果某個公共元素的ab的順序不同,它就不會遵守驗證條件,但是在那種情況下,問題沒有解決的辦法。

在最簡單的情況下,只有一個不同的元素並且它處於相同的位置,只是通過兩個字符串進行迭代連接

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

如果您的列表比較復雜,請先將其中一個列表變成字典,然后在合並時對照另一個列表。

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

注意:很明顯,字符串無法正確地進行比較,您可能需要為此使用字典!

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM