ホームページ  >  記事  >  バックエンド開発  >  Python で 2 つの辞書 (dict) をエレガントにマージする方法

Python で 2 つの辞書 (dict) をエレガントにマージする方法

不言
不言オリジナル
2018-06-02 15:44:371671ブラウズ

辞書は、Python 言語の唯一のマッピング タイプです。次の記事では、Python で 2 つの辞書 (dict) をエレガントに結合する方法について主に説明します。コードが詳しく紹介されていますので、必要な方はぜひ参考にしてみてください。

はじめに

Dictionary は Python の最も強力なデータ型の 1 つです。この記事では、2 つの辞書 (dict) を結合する Python の関連コンテンツを詳しく紹介し、参考と学習のために共有します。では、詳しい紹介を見てみましょう。

2 つの辞書をマージするための 1 行のコード

2 つの辞書 x と y があると仮定し、x と y の値を変更せずにそれらを新しい辞書にマージします。たとえば

 x = {'a': 1, 'b': 2}
 y = {'b': 3, 'c': 4}

新しい結果 Z が得られることを期待します。キーが同じであれば、y は x をカバーします。望ましい結果は

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

PEP448 では実装できる新しい構文があり、この構文は python3.5 でサポートされています。 マージされたコードは次のとおりです

z = {**x, **y}

コードの。 多くの人がまだ python2 を使用しているため、python2 および python3.0 ~ python3.4 を使用している人には、より洗練された方法がありますが、それには 2 行のコードが必要です。

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

上記の方法では、yがxの内容をカバーすることになるので、最終的な結果はb=3になります

python3.5を使わずに一行で完成させる方法

Python 3.5 をまだ使用したことがない場合、または下位互換性のあるコードを作成する必要があり、それを 1 つの式で実行したい場合、最も効率的な方法は、それを関数に入れることです:

def merge_two_dicts(x, y):
 """Given two dicts, merge them into a new dict as a shallow copy."""
 z = x.copy()
 z.update(y)
 return z

次に 1 行

 z = merge_two_dicts(x, y)

def merge_dicts(*dict_args):
 """
 Given any number of dicts, shallow copy and merge into a new dict,
 precedence goes to key value pairs in latter dicts.
 """
 result = {}
 for dictionary in dict_args:
 result.update(dictionary)
 return result

など、複数の辞書をマージする関数を定義することもできます。その後、次のように使用できます

z = merge_dicts(a, b, c, d, e, f, g)

それらの場合、同じキーが前のキーをカバーします。

いくつかのそれほどエレガントではないデモ

items

この方法を使用する人もいます:

 z = dict(x.items() + y.items())

これは実際にメモリ内に 2 つのリストを作成し、その後 3 番目のリストを作成します。コピーが完了したら、新しい辞書を作成し、最初の 3 つのリストを削除します。このメソッドはパフォーマンスを消費し、Python3 では items() がオブジェクトを返すため、これを正常に実行できません。

>>> c = dict(a.items() + b.items())
Traceback (most recent call last):
 File "<stdin>", line 1, in <module>
TypeError: unsupported operand type(s) for +: &#39;dict_items&#39; and 
&#39;dict_items&#39;

z = dict(list(x.items()) + list(y.items())) のように明示的にリストにキャストする必要があります。これも同様ですパフォーマンスの無駄。 さらに、 items() によって返されるリストに基づく Union メソッドも python3 では失敗します。さらに、union メソッドは繰り返される key の値に不確実性をもたらすため、優先順位の要件がある場合に使用します。 2 つの辞書をマージする場合、この方法はまったく不適切です。 z = dict(list(x.items()) + list(y.items())) ,这太浪费性能了。 另外,想以来于items()返回的list做并集的方法对于python3来说也会失败,而且,并集的方法,导致了重复的key在取值时的不确定,所以,如果你对两个dict合并有优先级的要求,这个方法就彻底不合适了。

>>> x = {&#39;a&#39;: []}
>>> y = {&#39;b&#39;: []}
>>> dict(x.items() | y.items())
Traceback (most recent call last):
 File "<stdin>", line 1, in <module>
TypeError: unhashable type: &#39;list&#39;

这里有一个例子,其中y应该具有优先权,但是由于任意的集合顺序,x的值被保留:

>>> x = {&#39;a&#39;: 2}
>>> y = {&#39;a&#39;: 1}
>>> dict(x.items() | y.items())
{&#39;a&#39;: 2}

构造函数

也有人会这么用

z = dict(x, **y)

这样用很好,比前面的两步的方法高效多了,但是可阅读性差,不够pythonic,如果当key不是字符串的时候,python3中还是运行失败

>>> c = dict(a, **b)
Traceback (most recent call last):
 File "<stdin>", line 1, in <module>
TypeError: keyword arguments must be strings

Guido van Rossum 大神说了:宣告dict({}, {1:3})

{k: v for d in dicts for k, v in d.items()}
ここでは、y が優先されるべきですが、任意のセットの順序付けにより x の値が保持される例を示します。

 dict((k, v) for d in dicts for k, v in d.items())

を使用するのは非常に良い方法です。前の 2 段階の方法よりもはるかに効率的ですが、可読性が低く、キーが文字列でない場合、Python 3 では依然として操作が失敗します。

import itertools
z = dict(itertools.chain(x.iteritems(), y.iteritems()))

Guido van Rossum 氏は次のように述べています: dict({}, {1:3}) の宣言は結局のところメカニズムの悪用なので違法です。この方法はよりハック的ではありますが、あまりにもご都合主義的です。

パフォーマンスは低いがよりエレガントないくつかのメソッド

以下のメソッドは、パフォーマンスは低いですが、items メソッドよりもはるかに優れています。そして優先順位をサポートします。

>>> min(timeit.repeat(lambda: merge_two_dicts(x, y)))
0.5726828575134277
>>> min(timeit.repeat(lambda: {k: v for d in (x, y) for k, v in d.items()} ))
1.163769006729126
>>> min(timeit.repeat(lambda: dict(itertools.chain(x.iteritems(),y.iteritems()))))
1.1614501476287842
>>> min(timeit.repeat(lambda: dict((k, v) for d in (x, y) for k, v in d.items())))
2.2345519065856934

Python2.6 では、これを行うことができます

>>> min(timeit.repeat(lambda: {**x, **y}))
0.4094954460160807
>>> min(timeit.repeat(lambda: merge_two_dicts(x, y)))
0.7881555100320838
>>> min(timeit.repeat(lambda: {k: v for d in (x, y) for k, v in d.items()} ))
1.4525277839857154
>>> min(timeit.repeat(lambda: dict(itertools.chain(x.items(), y.items()))))
2.3143140770262107
>>> min(timeit.repeat(lambda: dict((k, v) for d in (x, y) for k, v in d.items())))
3.2069112799945287

itertools.chain は、キーと値のペアのイテレータを正しい順序でチェーンします

rrreee

パフォーマンステスト

🎜🎜以下は、Python 2.7 (システム Python) の Ubuntu 14.04 で実行されました: 🎜🎜🎜rrreee🎜🎜🎜 in python3.5 🎜

以上がPython で 2 つの辞書 (dict) をエレガントにマージする方法の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。