2013-08-18 45 views
4

我有兩個相同排序類型的值列表,它們按升序排序,但(i)它們不具有相同的長度,以及(ii)條目出現在一個列表中可能會從另一個列表中丟失,反之亦然。但是我知道一個列表中的大多數值都存在於另一個列表中,並且在任何列表中都沒有重複。如果碰巧值從兩個列表的順序是通過爲缺失條目添加特殊值來對齊兩個列表

list1 = [value1-0, value1-1, value1-2, value1-3] 
list2 = [value2-0, value2-1, value2-2] 

所以我們可以有這種情況

value1-0 < (value1-1 = value2-0) < value2-1 < value1-2 < value1-3 < value2-2 

我們可以給合併排序值名稱爲的值,例如:

valueA < valueB < valueC < valueD < valueE < valueF 

so這兩個表可以寫成:

list1 = [valueA, valueB, valueD, valueE] 
list2 = [valueB, valueC, valueF] 

鑑於這種我想要的清單成爲:

new_list1 = [valueA, valueB, "MISSING", valueD, valueE, "MISSING"] 
new_list2 = ["MISSING", valueB, valueC, "MISSING", "MISSING", valueF ] 

誰能幫助?

編輯:稱爲特別datetime對象(因此具體到datetime S上的評論)的原來的問題,但已被推廣到任意類型的排序。

+0

當你不知道時,你如何確定最終名單的順序ow是日期時間對象的相對順序?即什麼迫使最後兩個元素是「E」然後是「F」?爲什麼不'F'然後'E'? – arshajii

+0

對不起,這可能有點混亂。我看到了你刪除的答案,這是我想要的,但在你刪除它之後投票。我的意思就是說,例如,如果你看看'list1''內的_,那麼絕對順序是:{{A - > A,B - > B,D - > C,E - > D}'。我在問題中提出的兩個列表之間的組合(或相對)編號基本上是在應用解決方案後實現的。它是'(E,F)'而不是'(F,E)',因爲'datetimeE

+0

欲瞭解完整性,請參閱[pandas](http://pandas.pydata.org/pandas-docs/dev/merging.html)。它完全是爲了這種數據操作而編寫的。 –

回答

4

怎麼是這樣的:

set1 = set(list1) 
set2 = set(list2) 
total = sorted(set1|set2) 

new_list1 = [x if x in set1 else "MISSING" for x in total] 
new_list2 = [x if x in set2 else "MISSING" for x in total] 
+0

由於顯然這些元素不需要是'datetime'對象,而是任何可排序的對象,我應該推廣這個問題嗎? –

+0

@OrestisTsinalis這完全取決於你。對於其他人來說,如果將它概括化,未來可能會對你的問題有所幫助,但我相信大多數人可以自己做出這些概括。 – arshajii

+0

如果源列表中有重複的元素,這將不起作用。 –

1

你可以嘗試:

new_list1=[] 
new_list2=[] 

i=j=0 
while True: 
    print '1 ' + str(new_list1) +' '+str(i) 
    print '2 ' + str(new_list2) +' '+str(j) 
    if list1[i]==list2[j]: 
     new_list1 += [list1[i]] 
     new_list2 += [list2[j]] 
     i=i+1 
     j=j+1 
    elif list1[i]>list2[j]: 
     new_list1 += ["MISSING"] 
     new_list2 += [list2[j]] 
     j=j+1 
    else: # list1[i]<list2[j] 
     new_list1 += [list1[i]] 
     new_list2 += ["MISSING"] 
     i=i+1 
    if i>=len(list1) or j>=len(list2): 
     break 
while i<len(list1): 
    new_list1 += [list1[i]] 
    new_list2 += ["MISSING"] 
    i=i+1 
while j<len(list2): 
    new_list1 += ["MISSING"] 
    new_list2 += [list2[j]] 
    j=j+1 

它看起來像一個大量的代碼,但它應該工作以及遍歷列表一次。

+0

只要將'if> = len(list1)或j> = len(list2):'塊移動到循環的開頭,就可以正確處理空列表。 –

1

這個問題引起了我的興趣,所以我寫了一個過於通用的解決方案。

這裏的一個函數,

  • 對準任何數量上的迭代序列
  • 作品的,所以它可以有效地處理長(或無限的)序列
  • 支持重複的值
  • 是與Python兼容2和3(儘管如果我不關心歷史Python版本,我會使用align_iterables(*inputs, missing_value=None)

import itertools 

def align_iterables(inputs, missing=None): 
    """Align sorted iterables 

    Yields tuples with values from the respective `inputs`, placing 
    `missing` if the value does not exist in the corresponding 
    iterable. 

    Example: align_generator('bc', 'bf', '', 'abf') yields: 
     (None, None, None, 'a') 
     ('b', 'b', None, 'b') 
     ('c', None, None, None) 
     (None, 'f', None, 'f') 
    """ 
    End = object() 
    iterators = [itertools.chain(i, [End]) for i in inputs] 
    values = [next(i) for i in iterators] 
    while not all(v is End for v in values): 
     smallest = min(v for v in values if v is not End) 
     yield tuple(v if v == smallest else missing for v in values) 
     values = [next(i) if v == smallest else v 
        for i, v in zip(iterators, values)] 

#對這個問題的問題的適配器:

def align_two_lists(list1, list2, missing="MISSING"): 
    value = list(zip(*list(align_iterables([list1, list2], missing=missing)))) 
    if not value: 
     return [[], []] 
    else: 
     a, b = value 
     return [list(a), list(b)] 

#A組爲問題的問題測試:

if __name__ == '__main__': 
    assert align_two_lists('abcef', 'abcdef', '_') == [['a', 'b', 'c', '_', 'e', 'f'], ['a', 'b', 'c', 'd', 'e', 'f']] 
    assert align_two_lists('a', 'abcdef', '_') == [['a', '_', '_', '_', '_', '_'], ['a', 'b', 'c', 'd', 'e', 'f']] 
    assert align_two_lists('abcdef', 'a', '_') == [['a', 'b', 'c', 'd', 'e', 'f'], ['a', '_', '_', '_', '_', '_']] 
    assert align_two_lists('', 'abcdef', '_') == [['_', '_', '_', '_', '_', '_'], ['a', 'b', 'c', 'd', 'e', 'f']] 
    assert align_two_lists('abcdef', '', '_') == [['a', 'b', 'c', 'd', 'e', 'f'], ['_', '_', '_', '_', '_', '_']] 
    assert align_two_lists('ace', 'abcdef', '_') == [['a', '_', 'c', '_', 'e', '_'], ['a', 'b', 'c', 'd', 'e', 'f']] 
    assert align_two_lists('bdf', 'ace', '_') == [['_', 'b', '_', 'd', '_', 'f'], ['a', '_', 'c', '_', 'e', '_']] 
    assert align_two_lists('ace', 'bdf', '_') == [['a', '_', 'c', '_', 'e', '_'], ['_', 'b', '_', 'd', '_', 'f']] 
    assert align_two_lists('aaacd', 'acd', '_') == [['a', 'a', 'a', 'c', 'd'], ['a', '_', '_', 'c', 'd']] 
    assert align_two_lists('acd', 'aaacd', '_') == [['a', '_', '_', 'c', 'd'], ['a', 'a', 'a', 'c', 'd']] 
    assert align_two_lists('', '', '_') == [[], []] 

    list1 = ["datetimeA", "datetimeB", "datetimeD", "datetimeE"] 
    list2 = ["datetimeB", "datetimeC", "datetimeD", "datetimeF"] 

    new_list1 = ["datetimeA", "datetimeB", "MISSING", "datetimeD", "datetimeE", "MISSING"] 
    new_list2 = ["MISSING", "datetimeB", "datetimeC", "datetimeD", "MISSING", "datetimeF"] 

    assert align_two_lists(list1, list2) == [new_list1, new_list2] 

#和一些額外的測試:

# Also test multiple generators 
    for expected, got in zip(
      [(None, None, None, 'a'), 
      ('b', 'b', None, 'b'), 
      ('c', None, None, None), 
      (None, 'f', None, 'f')], 
      align_iterables(['bc', 'bf', '', 'abf'])): 
     assert expected == got 

    assert list(align_iterables([])) == [] 

    # And an infinite generator 
    for expected, got in zip(
      [(0, 0), 
      ('X', 1), 
      (2, 2), 
      ('X', 3), 
      (4, 4)], 
      align_iterables([itertools.count(step=2), itertools.count()], missing='X')): 
     assert expected == got 
相關問題