キー/値を宣言されたのと同じ順序に保つ方法は?


320

特定の順序で宣言した辞書があり、その順序で常に保持したい。キー/値は、実際にはそれらの値に基づいた順序で保持することはできません。宣言した順序にしたいだけです。

だから私が辞書を持っているなら:

d = {'ac': 33, 'gw': 20, 'ap': 102, 'za': 321, 'bs': 10}

それを表示したり繰り返し処理したりした場合、その順序ではありません。キー/値を宣言した明示的な順序をPythonが確実に維持する方法はありますか?

回答:


229

Python 3.6以降、標準dictタイプはデフォルトで挿入順序を維持します。

定義

d = {'ac':33, 'gw':20, 'ap':102, 'za':321, 'bs':10}

ソースコードにリストされている順序でキーを持つ辞書になります。

これは、スパースハッシュテーブルに整数を含む単純な配列を使用して実現されました。これらの整数は、キーと値のペア(および計算されたハッシュ)を格納する別の配列にインデックスを付けます。後者の配列は、たまたま挿入順に項目を格納するだけであり、組み合わせ全体が実際に使用するメモリは、Python 3.5以前で使用されていた実装よりも少なくなっています。詳細については、レイモンドヘッティンガーによるオリジナルのアイデアの投稿を参照してください。

3.6では、これは実装の詳細と見なされていました。Python 3.6の新機能のドキュメントをご覧ください。

この新しい実装の順序を維持する側面は、実装の詳細と見なされ、信頼すべきではありません(これは将来変更される可能性がありますが、言語仕様を変更する前に、この新しいdict実装をいくつかのリリースで使用することが望まれます)現在および将来のすべてのPython実装に対して順序を維持するセマンティクスを義務付けるために、これは、ランダムな反復順序がまだ有効である古いバージョンの言語(Python 3.5など)との下位互換性を維持するのにも役立ちます。

Python 3.7では、この実装の詳細が言語仕様に引き上げられてdictいるため、そのバージョン以降と互換性のあるすべてのPython実装で順序を維持することが必須になりました。BDFLによる発音を参照してください。

標準型に加えていくつかの追加機能を提供しているため、特定の場合にはcollections.OrderedDict()クラスを使用することもできますdict。そのようなものとしてとして可逆(このまで延びビュー・オブジェクト)、及び(VIAリオーダリング支援move_to_end()方法)。


残念ながら、これは辞書の作成には関係ありません。コードの例のように指定された辞書は、同じ順序を維持することが保証されていません。つまり、空の辞書を作成し、順序を制御したい場合は各要素を手動で挿入する必要があります。
naught101

8
@ naught101:いいえ、これ dictの作成に適用されます。Python 3.7以降では、質問に示されているようにdictディスプレイを使用すると、これらのキーが順番にリストされることが保証されます。キーと値のペア書き込まれたので、左から右へと挿入されている言語仕様保証キー/基準ペアのカンマで区切られた配列が与えられた場合、それらは辞書のエントリを定義するために左から右に評価されますdict()ドキュメントはさえ例が含まれています。
Martijn Pieters

175
from collections import OrderedDict
OrderedDict((word, True) for word in words)

含む

OrderedDict([('He', True), ('will', True), ('be', True), ('the', True), ('winner', True)])

値がTrue(またはその他の不変オブジェクト)の場合は、次のものも使用できます。

OrderedDict.fromkeys(words, True)

2
もちろん、「不変」の部分は、Pythonが適用する厳格な規則ではないことに注意してください。その「唯一の」良いアイデアです。
lvc

11
次のような解決策は注意してください:OrderedDict(FUTURE=[], TODAY=[], PAST=[])アプローチについて言及した場合、機能しません:OrderedDict([('FUTURE', []), ('TODAY', []), ('PAST', [])])順序を維持します。
andilabs 2014年

2
@andi別の問題が発生しました。jsonifyを使用すると、jsonデータを生成するときにOrderedDictの順序が失われているようです。これを解決するにはどうしますか?
tyan 2016年

github.com/pallets/flask/issues/974この問題を解決するために使用することができます。..
TYAN

5
Python3.7には、デフォルトでdictが順序付けされています。mail.python.org/pipermail/python-dev/2017-December/151283.html
sertsedat

167

理論的な部分を説明するのではなく、簡単な例を示します。

>>> from collections import OrderedDict
>>> my_dictionary=OrderedDict()
>>> my_dictionary['foo']=3
>>> my_dictionary['aol']=1
>>> my_dictionary
OrderedDict([('foo', 3), ('aol', 1)])
>>> dict(my_dictionary)
{'foo': 3, 'aol': 1}

16
DictタイプのようにOrderedDictを一括で割り当てる方法はありますか?
tyan 2016年

2
OrderedDict確かに問題は解決しますが、この特定の例では、標準の辞書を使用してまったく同じ結果が得られます
Tonechas

2
@Tonechas:私は標準の辞書で例を試してみましたが、{'aol': 1, 'foo': 3}それは良い説明例だと思います。
twasbrillig

4
みんなのための教訓があります:Pythonの予測可能なハッシュがセキュリティの脆弱性を引き起こす可能性があることが発見された(私は2.4リリースのあたりだと思う)ので、同じコードの2つの異なる実行でも標準で同じ順序を与える保証はありませんdict。
holdenweb 2016

1
@tyan OrderedDict.update()は、キーと値のペアを含むイテラブルで呼び出すことができますd1.upate([(key1, val1), (key2, val2)])
Ruud Althuizen

37

この回答はpython3.7より前のバージョンのpythonに適用されることに注意してください。CPython 3.6は、ほとんどの状況で実装の詳細として挿入順序を維持します。Python3.7以降、実装では、挿入順序を維持して準拠させる必要があると宣言されています。


Python辞書は順不同です。順序付けされた辞書が必要な場合は、collections.OrderedDictを試してください。

OrderedDictは、Python 2.7の標準ライブラリに導入されたことに注意してください。古いバージョンのPythonを使用している場合は、順序付き辞書のレシピをActiveStateで見つけることができます。


上記の@martijnの投稿を参照してください。Python 3.6以降では、dictは挿入順序をサポートしています。
tpk

13

辞書は、検索を効率的にする順序を使用します。これを変更することはできません。

オブジェクトのリスト(単純な場合は2要素のタプル、またはクラス)を使用して、最後に項目を追加するだけです。その後、線形検索を使用して、その中のアイテムを見つけることができます。

または、順序を維持するために作成された別のデータ構造を作成または使用することもできます。


辞書は検索を効率的する順序を使用します最後に、誰かがそれを指摘しました。
scharette

7

OrderedDictを機能させる方法を理解しようとしているときに、この投稿に遭遇しました。PyDev for EclipseはOrderedDictをまったく見つけることができなかったので、注文したい辞書のキー値のタプルを作成することにしました。リストを出力する必要があるときは、タプルの値を反復処理し、反復した「キー」をタプルからディクショナリにプラグインして、必要な順序で値を取得しました。

例:

test_dict = dict( val1 = "hi", val2 = "bye", val3 = "huh?", val4 = "what....")
test_tuple = ( 'val1', 'val2', 'val3', 'val4')
for key in test_tuple: print(test_dict[key])

それは少し面倒ですが、私は時間を求められており、それは私が思いついた回避策です。

注:リストの順序付けとインデックス付けが行われているため(また、辞書とは構造が異なるため)、他の誰かが提案したリストリストのアプローチは実際には意味がありません。


素晴らしいソリューション。私はそれを使用して、常に同じ順序でjsonをファイルに書き込みます。
Hrvoje T

6

あなたは本当に辞書でやりたいことはできません。辞書はすでにd = {'ac':33, 'gw':20, 'ap':102, 'za':321, 'bs':10}作成されています。既に作成されているため、整理する方法がないことがわかりました。私がしたことは、代わりにオブジェクトでjsonファイルを作成することでした:

{"ac":33,"gw":20,"ap":102,"za":321,"bs":10}

私が使用した:

r = json.load(open('file.json'), object_pairs_hook=OrderedDict)

次に使用:

print json.dumps(r)

検証します。


1
それでは、リストのOrderedDictから始めてみませんか?JSONファイルは、実際には何も追加しません。
Martijn Pieters

はい、リストは順序を維持するのに役立ちますが、答えは辞書の順序付けに関する質問に関するものでした。辞書を使用することの制限について人々に知らせ、何らかの理由で辞書を使用する必要がある場合は、回避策を提供するだけです。
nealous3 2017年

1
しかし、その一部はすでに2012年にさかのぼる、ずっと年上の回答で覆われている
マルタインピータース

3
from collections import OrderedDict
list1 = ['k1', 'k2']
list2 = ['v1', 'v2']
new_ordered_dict = OrderedDict(zip(list1, list2))
print new_ordered_dict
# OrderedDict([('k1', 'v1'), ('k2', 'v2')])

もはや口述ではない主な問題、それはタプルのリストです
Oleg

2

もう1つの方法は、Pandasを使用するdataframeことです。これは、dictのような構造でアイテムの順序とインデックスの場所を保証するためです。


1

一般的に、あなたは辞書のように振る舞うが、主にメソッドを実装することをクラス設計することができ__contains____getitem____delitem____setitem__およびいくつかのより多くを。そのクラスはあなたが好きな振る舞いを持つことができます。例えば、キーの上にソートされたイテレータを提供する...


1

辞書を特定の順序で配置したい場合は、リストのリストを作成することもできます。最初の項目がキー、2番目の項目が値となり、次の例のようになります。

>>> list =[[1,2],[2,3]]
>>> for i in list:
...     print i[0]
...     print i[1]

1
2
2
3

7
コレクション全体を検索しないと(O(n)時間をかけて)、キーで項目を検索できないため、これは「辞書」ではありません。
BHSPitMonkey 2014年

1
はい、それは辞書ではありませんが、状況によっては、元の投稿者の問題の有効な解決策を提供する可能性があります。
SunSparc

彼は、私たちがどのようにしたいかを正確に言っていませんでした。
ペロス2018年

1

Djangoプロジェクトの開発時にも同様の問題がありました。古いバージョンのpythonを実行していたため、OrderedDictを使用できなかったため、解決策はDjangoのSortedDictクラスを使用することでした。

https://code.djangoproject.com/wiki/SortedDict

例えば、

from django.utils.datastructures import SortedDict
d2 = SortedDict()
d2['b'] = 1
d2['a'] = 2
d2['c'] = 3

注:この回答は2011年のものです。Pythonバージョン2.7以降にアクセスできる場合は、現在標準collections.OrderedDictとなっているにアクセスできるはずです。その多くの例がこのスレッドの他のユーザーから提供されています。


0

辞書の場合と同じことができます。

リストと空の辞書を作成します。

dictionary_items = {}
fields = [['Name', 'Himanshu Kanojiya'], ['email id', 'hima@gmail.com']]
l = fields[0][0]
m = fields[0][1]
n = fields[1][0]
q = fields[1][1]
dictionary_items[l] = m
dictionary_items[n] = q
print dictionary_items
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.