我想将两个词典融入一个新的词典。

x = {'a': 1, 'b': 2}
y = {'b': 3, 'c': 4}
z = merge(x, y)

>>> z
{'a': 1, 'b': 3, 'c': 4}

每当两个字典中都有一个关键 k 时,只应保留 y(k) 的值。


当前回答

我想要一些类似的东西,但有能力说明双键中的值是如何合并的,所以我打破了这个(但没有重量测试)。

def merge(d1, d2, merge_fn=lambda x,y:y):
    """
    Merges two dictionaries, non-destructively, combining 
    values on duplicate keys as defined by the optional merge
    function.  The default behavior replaces the values in d1
    with corresponding values in d2.  (There is no other generally
    applicable merge strategy, but often you'll have homogeneous 
    types in your dicts, so specifying a merge technique can be 
    valuable.)

    Examples:

    >>> d1
    {'a': 1, 'c': 3, 'b': 2}
    >>> merge(d1, d1)
    {'a': 1, 'c': 3, 'b': 2}
    >>> merge(d1, d1, lambda x,y: x+y)
    {'a': 2, 'c': 6, 'b': 4}

    """
    result = dict(d1)
    for k,v in d2.iteritems():
        if k in result:
            result[k] = merge_fn(result[k], v)
        else:
            result[k] = v
    return result

其他回答

z = MergeDict(x, y)

当使用这个新对象时,它将像合并词典一样行事,但它将有持续的创作时间和持续的记忆脚印,同时让原始词典无触摸。

当然,如果你使用结果很多,那么你会在某个时候达到创建一个真正的合并词典会是最快的解决方案的界限。

a = { 'x': 3, 'y': 4 }
b = MergeDict(a)  # we merge just one dict
b['x'] = 5
print b  # will print {'x': 5, 'y': 4}
print a  # will print {'y': 4, 'x': 3}

class MergeDict(object):
  def __init__(self, *originals):
    self.originals = ({},) + originals[::-1]  # reversed

  def __getitem__(self, key):
    for original in self.originals:
      try:
        return original[key]
      except KeyError:
        pass
    raise KeyError(key)

  def __setitem__(self, key, value):
    self.originals[0][key] = value

  def __iter__(self):
    return iter(self.keys())

  def __repr__(self):
    return '%s(%s)' % (
      self.__class__.__name__,
      ', '.join(repr(original)
          for original in reversed(self.originals)))

  def __str__(self):
    return '{%s}' % ', '.join(
        '%r: %r' % i for i in self.iteritems())

  def iteritems(self):
    found = set()
    for original in self.originals:
      for k, v in original.iteritems():
        if k not in found:
          yield k, v
          found.add(k)

  def items(self):
    return list(self.iteritems())

  def keys(self):
    return list(k for k, _ in self.iteritems())

  def values(self):
    return list(v for _, v in self.iteritems())

我将所提出的与 perfplot 比较,并发现

x | y   # Python 3.9+

是最快的解决方案,与旧的好解决方案

{**x, **y}

temp = x.copy()
temp.update(y)

此分類上一篇


重复字符的代码:

from collections import ChainMap
from itertools import chain
import perfplot


def setup(n):
    x = dict(zip(range(n), range(n)))
    y = dict(zip(range(n, 2 * n), range(n, 2 * n)))
    return x, y


def copy_update(x, y):
    temp = x.copy()
    temp.update(y)
    return temp


def add_items(x, y):
    return dict(list(x.items()) + list(y.items()))


def curly_star(x, y):
    return {**x, **y}


def chain_map(x, y):
    return dict(ChainMap({}, y, x))


def itertools_chain(x, y):
    return dict(chain(x.items(), y.items()))


def python39_concat(x, y):
    return x | y


b = perfplot.bench(
    setup=setup,
    kernels=[
        copy_update,
        add_items,
        curly_star,
        chain_map,
        itertools_chain,
        python39_concat,
    ],
    labels=[
        "copy_update",
        "dict(list(x.items()) + list(y.items()))",
        "{**x, **y}",
        "chain_map",
        "itertools.chain",
        "x | y",
    ],
    n_range=[2 ** k for k in range(18)],
    xlabel="len(x), len(y)",
    equality_check=None,
)
b.save("out.png")
b.show()

2 词典

def union2(dict1, dict2):
    return dict(list(dict1.items()) + list(dict2.items()))

n 字典

def union(*dicts):
    return dict(itertools.chain.from_iterable(dct.items() for dct in dicts))

查看 https://mathieularose.com/how-not-to-flatten-a-list-of-lists-in-python/

我认为我的丑陋的单线只需要在这里。

z = next(z.update(y) or z for z in [x.copy()])
# or
z = (lambda z: z.update(y) or z)(x.copy())

单一表达,永远不要敢用它。

我知道Python 3有这个 {**x, **y} 事物,它是正确的事情使用(以及转到Python 3 如果你仍然有Python 2是正确的事情)。

>>> x = {'a':1, 'b': 2}
>>> y = {'b':10, 'c': 11}
>>> x, z = dict(x), x.update(y) or x
>>> x
{'a': 1, 'b': 2}
>>> y
{'c': 11, 'b': 10}
>>> z
{'a': 1, 'c': 11, 'b': 10}