Pythonでは、ソートされたキーの順序で辞書をどのように反復しますか?


211

次で終わる既存の関数があります。dは辞書です。

return d.iteritems()

これは、指定された辞書のソートされていないイテレータを返します。キーでソートされたアイテムを通過するイテレータを返したいのですが。それ、どうやったら出来るの?

回答:


171

これはあまりテストされていませんが、Python 2.5.2で動作します。

>>> d = {"x":2, "h":15, "a":2222}
>>> it = iter(sorted(d.iteritems()))
>>> it.next()
('a', 2222)
>>> it.next()
('h', 15)
>>> it.next()
('x', 2)
>>>

for key, value in d.iteritems(): ...イテレータの代わりに行うことに慣れている場合、これは上記のソリューションでも機能します

>>> d = {"x":2, "h":15, "a":2222}
>>> for key, value in sorted(d.iteritems()):
>>>     print(key, value)
('a', 2222)
('h', 15)
('x', 2)
>>>

Python 3.xでは、d.items()代わりにd.iteritems()を使用してイテレータを返します。


29
使用.items()の代わりにiteritems():@Claudiuが言ったように、iteritemsは、Python 3.xのために働くのではなく、items()Pythonの2.6から入手可能です。
レミ

40
これは明白ではありません。実際にitems()は、リストを作成してメモリを使用しますが、iteritems()基本的にメモリは使用しません。何を使用するかは、主に辞書のサイズによって異なります。さらに、Python 2からPython 3への2to3自動変換ツール()がからiteritems()への変換を自動的items()に処理するので、これを心配する必要はありません。
Eric O Lebigot

5
@HowerHellを使用するとcollections.OrderedDict、一度ソートすると、常にソートされた順序でアイテムが取得されます。
Mark Harviston 2013年

9
ただし、@ EOLは、iteritems()メモリを使用しない場合でも、すべてをのメモリにプルする必要がsorted()あるため、items()との使用にiteritems()メモリ上の違いはありません。
Richard

8
@Richard:それはすべての要素がメモリ内に引き込まれなければならないことは事実ですが、それらがされて保存されて二回items()(から返されたリストの中items()だけで一回とし、ソートされたリスト内)iteritems()(ソートされたリストでのみ)。
Eric O Lebigot 2013年

83

sorted()関数を使用します。

return sorted(dict.iteritems())

ソートされた結果に対する実際のイテレータが必要な場合sorted()は、リストを返すので、次を使用します。

return iter(sorted(dict.iteritems()))

それは私にとって失敗します:<type 'exceptions.TypeError'>:iter()はタイプ 'list'の非イテレータを返しました
mike

おそらく、変数名として「dict」を使用しているためです。「dict」は実際には辞書のタイプ名です。ここでは "mydict"のような別の名前を使用してください。
utku_karatas 2008

1
まだ動作していません。通常のリストではなく、sorted()が別のイテレータを返すことを確認していますか?
マイク

この例外はいつどこで発生しますか?問題なくリストを反復処理できます

1
同意し、ホップ。ファイルの行をスキップする場合を除いて、.next()を直接呼び出すことはないと思います。私たちのiter(sorted(dict.iteritems()))ソリューションは、とにかく「sorted(」ステージでメモリ内のdict全体のコピーを作成するため、主要なイテレータの利点は失われたようです:)

39

dictのキーはハッシュテーブルに保存されるので、「自然な順序」、つまり疑似ランダムになります。他のすべての順序は、辞書の消費者の概念です。

sorted()は、dictではなく常にリストを返します。dict.items()(タプルのリストを生成する)を渡すと、ループで使用できるタプル[(k1、v1)、(k2、v2)、...]のリストが返されます。非常に口述に似ていますが、とにかく口述ではありません

foo = {
    'a':    1,
    'b':    2,
    'c':    3,
    }

print foo
>>> {'a': 1, 'c': 3, 'b': 2}

print foo.items()
>>> [('a', 1), ('c', 3), ('b', 2)]

print sorted(foo.items())
>>> [('a', 1), ('b', 2), ('c', 3)]

以下はループ内のdictのように感じますが、そうではありません。k、vにアンパックされるタプルのリストです。

for k,v in sorted(foo.items()):
    print k, v

ほぼ同等:

for k in sorted(foo.keys()):
    print k, foo[k]

わかりましたが、DictやListは必要ありません。Iteratorが必要です。イテレーターになるように強制するにはどうすればよいですか?
マイク

2
sorted(foo.keys())sorted(foo)ディクショナリは反復時にキーを返すため、同等のものよりも優れています(foo.keys()中間リストの作成を強制されないという利点があるかもしれません- sorted()イテラブルの実装方法によって異なります)。
エリックOレビゴット2014

速度および/またはメモリのためのより良いですワンダーk in sorted(foo.keys()):キーを引っ張るか、for k,v in sorted(foo.items()):私は推測する辞書のリストのペアのコピーを返しますsorted(foo.keys())
CrandellWS

1
@CrandellWS:時間の質問に答える最良の方法は、Python timeitモジュールを使用することです。
Peter Rowell、2015年

1
@frank-短い回答:いいえ。dictは配列であり、実際のキーは指定されたキーの値のハッシュです。かなり予測可能な実装もあれば、この契約を結ぶ実装もあるかもしれませんが、ハッシュの順序に関しては何も当てになりません。3.6以上の動作の詳細については、この投稿を参照してください。特に最初の答えに注意してください。
Peter Rowell

31

グレッグの答えは正しい。Python 3.0では、次のことを行う必要があることに注意してください。

sorted(dict.items())

iteritems消えてしまうように。


それは私にとって失敗します:<type 'exceptions.TypeError'>:iter()はタイプ 'list'の非イテレータを返しました
mike

3
「将来的にはホバーボードができるので、車を利用しないでください」
JJ

7

OrderedDictPython 2.7でも使用できるようになりました。

>>> from collections import OrderedDict
>>> d = OrderedDict([('first', 1),
...                  ('second', 2),
...                  ('third', 3)])
>>> d.items()
[('first', 1), ('second', 2), ('third', 3)]

ここに、2.7バージョンの新機能ページとOrderedDict APIがあります


これは、ソートされた順序(つまり、アルファベット順)ではなく、挿入された順序でキーと値を返します。
トニーサフォーク66

5

一般的に、次のように辞書を並べ替えることができます。

for k in sorted(d):
    print k, d[k]

質問の特定のケースでは、d.iteritems()の「ドロップイン置換」があり、次のような関数を追加します。

def sortdict(d, **opts):
    # **opts so any currently supported sorted() options can be passed
    for k in sorted(d, **opts):
        yield k, d[k]

なので、最終行は

return dict.iteritems()

return sortdict(dict)

または

return sortdict(dict, reverse = True)

5
>>> import heapq
>>> d = {"c": 2, "b": 9, "a": 4, "d": 8}
>>> def iter_sorted(d):
        keys = list(d)
        heapq.heapify(keys) # Transforms to heap in O(N) time
        while keys:
            k = heapq.heappop(keys) # takes O(log n) time
            yield (k, d[k])


>>> i = iter_sorted(d)
>>> for x in i:
        print x


('a', 4)
('b', 9)
('c', 2)
('d', 8)

このメソッドにはまだO(N log N)ソートがありますが、短い線形ヒープ化の後、アイテムはソート順にソートされ、リスト全体が常に必要なわけではない場合、理論的にはより効率的になります。



3

Sortedはリストを返すため、それを反復しようとするとエラーが発生しますが、dictを注文できないため、リストを処理する必要があります。

コードのより大きなコンテキストが何であるかはわかりませんが、結果のリストにイテレータを追加してみてください。このように多分?:

return iter(sorted(dict.iteritems()))

もちろん、ソートすると、dictがタプルのリストに変わったので、タプルが返されます。

例:辞書が次のとおりだったと言う: {'a':1,'c':3,'b':2} 並べ替えるとリストに変わります:

[('a',1),('b',2),('c',3)]

したがって、リストを実際に反復すると、(この例では)文字列と整数で構成されるタプルが返されますが、少なくともそれを反復することができます。


2

CPython 2.xを使用していて、大規模な辞書mydictがあるとすると、sorted(mydict)の使用は、sortedがmydictのキーのソート済みリストを作成するため、遅くなります。

その場合は、CのC実装を含む私のordereddictパッケージをsorteddict確認することをお勧めします。特に、辞書のライフタイムのさまざまな段階(つまり、要素の数)でソートされたキーのリストを何度も調べる必要がある場合。

http://anthon.home.xs4all.nl/Python/ordereddict/

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.