【问题标题】:Python: merging two lists where object "identity" isn't equalityPython:合并对象“身份”不相等的两个列表
【发布时间】:2014-09-13 21:04:45
【问题描述】:

我正在尝试合并两个列表,baseoverride,其中 base 应该是一个更大的列表,overridebase 中的一个子集。在元素重叠的地方,我希望base 中的对象被override 中的对象覆盖。每个列表中的对象都是命名元组,其中有属性al2000de2000。此外,当对象具有相同的 al2000de2000 值时,我想将它们视为“相同”。我所拥有的(似乎可行)如下,但这有嵌套循环,我想知道是否有更好的方法来做到这一点。

# Part of a function
final = []
for i in base:
    if all((i.al2000, i.de2000) != (k.al2000, k.de2000) for k in override):
        final.append(i)
    else:
        for k in override:
            if (i.al2000, i.de2000) == (k.al2000, k.de2000):
                final.append(k)
return final

【问题讨论】:

  • 在哪种情况下,您实际上会用覆盖中的项目覆盖基础中的项目?似乎您只想附加缺少的项目。

标签: python python-2.7


【解决方案1】:

您可以使用for/else 构造。

final = []
for i in base:
    for k in override:
        if (i.al2000, i.de2000) == (k.al2000, k.de2000):
            # found an override
            final.append(k)
            break
    else:
        final.append(i)

此解决方案仍然使用嵌套的 for 循环,但它从您的原始解决方案中删除了代码重复(迭代 overridesik 的比较)。

【讨论】:

    【解决方案2】:

    您可以使用字典和几个字典推导式。

    uniques = {(x.al2000, x.de2000): x for x in base}
    uniques.update({(x.al2000, x.de2000): x for x in override})
    final = uniques.values()
    

    编辑以保留有关在 override 中省略额外值的原始行为。

    uniques = {(x.al2000, x.de2000): x for x in base}
    for value in override:
        key = value.al2000, value.de2000
        if key in uniques:
            uniques[key] = value
    # here's the comprehension version, although it's a bit rough on the eyes
    # uniques.update({(x.al2000, x.de2000): x for x in override if (x.al2000, x.de2000) in uniques})
    final = uniques.values()
    

    【讨论】:

    • 这不等同于原始代码,因为 (1) 它不保留顺序 (2) override 中未出现在 base 中的元素包含在 final 中。否则,一个不错的优雅解决方案!
    • 我进行了编辑以解决第二个问题。第一个不能。另外,根据base 的大小,维护一个单独的结构(即uniques)可能会占用大量内存。
    【解决方案3】:

    这个答案采用了@acushner 的使用字典的建议,这可能是你情况下最自然的方法。此外,在处理覆盖时,ChainMap 很有用,并且在许多情况下是表示数据结构的最自然的方式。

    from collections import ChainMap
    base_dct = {(x.al2000, x.de2000): x for x in base}
    override_dct = {(x.al2000, x.de2000): x for x in override}
    z = ChainMap(base_dct, override_dct)
    # then access:
    z.values()
    # or:
    z[(x.al2000, x.de2000)]
    

    有关 ChainMaps 的更多信息,请参阅this question

    【讨论】:

      【解决方案4】:

      因为你真正想做的就是在覆盖中查找一些东西,所以用它做一个字典:

      od = {(x.al2000, x.de2000): x for x in override}
      

      现在,只需创建结果:

      res = [od.get((b.al2000, b.de2000), b) for b in base]
      

      *未测试,但应该没问题 *根据 dirn 的建议编辑

      【讨论】:

      • 您也可以将b 传递给od.get
      • 不,因为 b 的属性不仅仅是al2000de2000
      • 我的意思是od.get((b.al2000, b.de2000), b)
      猜你喜欢
      • 2023-01-17
      • 2021-09-10
      • 2022-11-15
      • 1970-01-01
      • 1970-01-01
      • 2017-03-23
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多