【问题标题】:python merge unsorted listspython合并未排序的列表
【发布时间】:2016-11-07 17:42:19
【问题描述】:

如何在保留的同时合并 2 个任意未排序列表 a 和 b 两个列表的顺序?我不想丢弃重复项或排序。 空白的格式只是为了让人类读者可视化:

a = ['a', 'b', 'c', 'X',       'Y',      '127'      ]
b = ['a', 'b',      'X', '44', 'Y', 'w', '127', 'X' ]

期望的输出m:

m = ['a', 'b', 'c', 'X', '44', 'Y', 'w', '127', 'X' ]

我应该更简洁地指定合并顺序。 匹配优先级进入列表a: 尝试将列表 a 中的每个项目与 b 中的项目匹配

So if  a = ['b',      'a', 'r', 'n']
and    b = ['b', 'r', 'a',      'n'],
merged m = ['b', 'r', 'a', 'r', 'n']

字典解决方案删除重复项(b[2] 和 b[7] 都是 'X')。

这需要是程序化的;我正在查看数百万行数据。 difflib 很有趣,可能是为了另一个问题,但我认为它对这个问题没有帮助。

我在 Windows-7 上使用 Python 2.7.12

下面的代码解决了这个问题,但没有我想的那么干净和简单。

def merge_lists(a, b):
    """ Merge 2 arbitrary unsorted lists a and b while preserving
    the order from both lists. Do not discard duplicates or sort."""

    ia = ib = 0
    m = []    
    if len(a) == 0:
        m = b
    elif len(b) == 0:
        m = a

    while ia < len(a) and ib < len(b):
        if a[ia] == b[ib]:
            m.append(a[ia])
            ia += 1
            ib += 1
        else:
            count = b[ib:].count(a[ia])
            if count == 0:
                m.append(a[ia])
                ia += 1
            else:
                k = b[ib:].index(a[ia])
                for i in range(ib, k+ib):
                    m.append(b[i])
                ib += k

        if ia >= len(a):
            for i in range(ib, len(b)):
                m.append(b[i])
        if ib >= len(b):
            for i in range(ia, len(a)):
                m.append(a[i])

    return m #--- END --- merge_lists()

【问题讨论】:

  • 欢迎来到Stack Overflow!您可能知道,SO 是一个问答网站。读者,比如你自己,提出问题,而其他读者试图回答这些问题。您的帖子缺少 SO 帖子的基本要素——问题!你的问题究竟是什么?
  • 在 a 和 b 的文字中插入空格的方式似乎未指定。请解释逻辑(这是编写代码的良好第一步。
  • 您没有很好地定义新列表的顺序:例如,说a=[1] 和b=[2] 结果应该是什么? [1,2] 或 [2,1] ?
  • 当你的两个列表是 ['b', 'a', 'r', 'n'] 和 ['b', 'r', 'a', 'n'] 时,你期望什么输出?

标签: python list merge


【解决方案1】:

您可能可以使用difflib,但您必须自己进行合并。这可能很棘手——而且在计算机上并不总是很容易做到(考虑何时必须在版本控制系统中手动合并冲突)。但是,很多情况可以自动处理。

这里有一些代码可以帮助您入门 - 我不保证它适用于所有情况,所以如果您发现有改进之处,请随时告诉我,我会尝试编辑它们:

a = ['a', 'b', 'c', 'X',       'Y',      '127'      ]
b = ['a', 'b',      'X', '44', 'Y', 'w', '127', 'X' ]
import difflib
matches = difflib.SequenceMatcher(a=a, b=b).get_matching_blocks()

# Pointers to locations in the `a` and `b` lists to keep track of our progress.
ix_a = 0
ix_b = 0
c = []
for match in matches:
    # Add in missing elements from `a` -- Assume `a` comes first?
    if match.a > ix_a:
        c.extend(a[ix_a: match.a])
    # add in missing elements from `b`
    if match.b > ix_b:
        c.extend(b[ix_b: match.b])
    # add in common elements.
    part = a[match.a:match.a + match.size]
    c.extend(part)

    # update our pointers into the original sequences.
    ix_a = match.a + match.size
    ix_b = match.b + match.size

print(c)

显然,difflib 选择匹配数据中的运行的确切方式有点儿摆布。例如@ZeroPiraeus 指出的示例:('barn' 和 'bran')1 导致 'brarn',但如果你颠倒输入的顺序,你会得到 'baran'。

这里令人惊讶的不是这两个结果是不同的——事实上,如果你改变输入的顺序,期望它们有不同的顺序是很自然的。但是,它们具有完全不同的值可能令人惊讶(一个有两个'r',另一个有两个'a')。

1为简洁起见,我将这些列表格式化为字符串。

【讨论】:

    【解决方案2】:

    没有一个正确的结果,因为问题已被指定。例如:

    a = ['b',      'r', 'a', 'n']
    b = ['b', 'a', 'r',      'n']
    m = ['b', 'a', 'r', 'a', 'n']
    

    a = ['b', 'r', 'a',      'n']
    b = ['b',      'a', 'r', 'n']
    m = ['b', 'r', 'a', 'r', 'n']
    

    【讨论】:

    • 有点困惑我是否应该投票赞成这个答案
    • @smac89 哦,你绝对应该;-)
    • @smac89 不那么轻率,this meta question 可能与您的困境有关。
    • 我同意那个元帖子。但是,我不一定同意它证明这个答案是正确的:-)。说“这是不可能的”与说“这是未指定的”非常不同。元帖子似乎在谈论前者,而这个答案试图说后者。在这种情况下,很可能任何一个 合并都是可以接受的。就个人而言,我觉得这作为对 OP 的评论会更好,表明需要进一步澄清。
    • @mgilson 这是临界点,我会同意的。促使我回答(而不是扩展我已经发表的评论)的是格式,包括空格,显着澄清了问题。我肯定会推动 OP 接受你的回答而不是我的回答,(并且只是因为我也没有正确阅读它而未能支持你的回答),但我仍然认为我的回答比评论更有启发性。不过,如果你觉得它值得一票否决,我不会特别难过。
    猜你喜欢
    • 2020-10-25
    • 2010-11-12
    • 2022-10-05
    • 2014-12-02
    • 2012-01-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多