8

我有两个相同可排序类型的值列表,它们按升序排序,但是(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

这样这两个列表就可以写成:

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对象(因此特定于datetimes 的评论),但已推广到任何可排序的类型。

4

3 回答 3

8

像这样的东西怎么样:

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]
于 2013-08-18T21:28:02.783 回答
7

这个问题引起了我的兴趣,所以我写了一个过于通用的解决方案。

这是一个函数

  • 对齐任意数量的序列
  • 适用于迭代器,因此它可以有效地处理长(或无限)序列
  • 支持重复值
  • 与 Python 2 和 3 兼容(尽管align_iterables(*inputs, missing_value=None)如果我不关心 Python 的历史版本,我会使用)

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

# 针对题目问题的一组测试:

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
于 2013-08-19T00:11:50.703 回答
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

它看起来像很多代码,但它应该可以工作并且只在列表中循环一次。

于 2013-08-18T22:13:37.357 回答