辞書を値で並べ替えるにはどうすればよいですか?

2009年03月05日に質問されました。  ·  閲覧回数 3.2M回  ·  ソース

Gern Blanston picture
2009年03月05日

データベースの2つのフィールド(文字列フィールドと数値フィールド)から読み取られた値の辞書があります。 文字列フィールドは一意であるため、それが辞書のキーです。

キーで並べ替えることはできますが、値に基づいて並べ替えるにはどうすればよいですか?

注:ここでStack Overflowの質問を読みました。辞書のリストを辞書の値で並べ替えるにはどうすればよいですか? おそらくコードを変更して辞書のリストを作成することもできますが、辞書のリストは実際には必要ないので、昇順または降順で並べ替えるより簡単な解決策があるかどうかを知りたいと思いました。

回答

Devin Jeanpierre picture
2009年03月05日
5342

Python3.7以降またはCPython3.6

ディクトはPython3.7以降で挿入順序を保持します。 CPython 3.6でも同じですが、実装の詳細です。

>>> x = {1: 2, 3: 4, 4: 3, 2: 1, 0: 0}
>>> {k: v for k, v in sorted(x.items(), key=lambda item: item[1])}
{0: 0, 2: 1, 1: 2, 4: 3, 3: 4}

または

>>> dict(sorted(x.items(), key=lambda item: item[1]))
{0: 0, 2: 1, 1: 2, 4: 3, 3: 4}

古いPython

辞書を並べ替えることはできません。並べ替えられた辞書の表現を取得するだけです。 辞書は本質的に順序がありませんが、リストやタプルなどの他のタイプはそうではありません。 したがって、ソートされた値を表すために順序付けられたデータ型が必要です。これはリスト(おそらくタプルのリスト)になります。

例えば、

import operator
x = {1: 2, 3: 4, 4: 3, 2: 1, 0: 0}
sorted_x = sorted(x.items(), key=operator.itemgetter(1))

sorted_xは、各タプルの2番目の要素でソートされたタプルのリストになります。 dict(sorted_x) == x

そして、値の代わりにキーでソートしたい人のために:

import operator
x = {1: 2, 3: 4, 4: 3, 2: 1, 0: 0}
sorted_x = sorted(x.items(), key=operator.itemgetter(0))

Python3では、解凍が許可され

x = {1: 2, 3: 4, 4: 3, 2: 1, 0: 0}
sorted_x = sorted(x.items(), key=lambda kv: kv[1])

出力をdictとして使用する場合は、 collections.OrderedDict使用できます。

import collections

sorted_dict = collections.OrderedDict(sorted_x)
Nas Banov picture
2010年07月05日
1339

シンプル: sorted(dict1, key=dict1.get)

ええと、実際には「辞書の値でソート」することは可能です。 最近、私はコードゴルフでそれをしなければなりませんでした(スタックオーバーフローの質問コードゴルフ:単語頻度チャート)。 要約すると、問題はそのようなものでした。テキストが与えられたら、各単語に遭遇する頻度を数え、頻度の低い順にソートされた上位の単語のリストを表示します。

単語をキーとして、各単語の出現回数を値として辞書を作成する場合、ここでは次のように簡略化されます。

from collections import defaultdict
d = defaultdict(int)
for w in text.split():
    d[w] += 1

次に、 sorted(d, key=d.get)を使用して、使用頻度順に並べられた単語のリストを取得できます。並べ替えは、単語の出現回数を並べ替えキーとして使用して、辞書キーを繰り返し処理します。

for w in sorted(d, key=d.get, reverse=True):
    print(w, d[w])

この詳細な説明は、「辞書はキーで簡単に並べ替えることができますが、値で並べ替えるにはどうすればよいか」という意味を説明するために書いています。元の投稿はそのような問題に対処しようとしていたと思います。 そして解決策は、上記のように、値に基づいてキーのリストを作成することです。

Mark picture
2010年02月14日
915

あなたが使用することができます:

sorted(d.items(), key=lambda x: x[1])

これにより、辞書内の各エントリの値によって辞書が最小から最大に並べ替えられます。

降順で並べ替えるには、 reverse=True追加するだけです。

sorted(d.items(), key=lambda x: x[1], reverse=True)

入力:

d = {'one':1,'three':3,'five':5,'two':2,'four':4}
a = sorted(d.items(), key=lambda x: x[1])    
print(a)

出力:

[('one', 1), ('two', 2), ('three', 3), ('four', 4), ('five', 5)]
Roberto Bonvallet picture
2009年03月05日
239

ディクトはソートできませんが、ディクトからソート済みリストを作成できます。

dict値のソートされたリスト:

sorted(d.values())

値でソートされた(キー、値)ペアのリスト:

from operator import itemgetter
sorted(d.items(), key=itemgetter(1))
mykhal picture
2010年07月05日
166

最近のPython2.7には、アイテムが追加された順序を記憶する新しい

>>> d = {"third": 3, "first": 1, "fourth": 4, "second": 2}

>>> for k, v in d.items():
...     print "%s: %s" % (k, v)
...
second: 2
fourth: 4
third: 3
first: 1

>>> d
{'second': 2, 'fourth': 4, 'third': 3, 'first': 1}

元の辞書から新しい順序付き辞書を作成するには、値で並べ替えます。

>>> from collections import OrderedDict
>>> d_sorted_by_value = OrderedDict(sorted(d.items(), key=lambda x: x[1]))

OrderedDictは、通常のdictのように動作します。

>>> for k, v in d_sorted_by_value.items():
...     print "%s: %s" % (k, v)
...
first: 1
second: 2
third: 3
fourth: 4

>>> d_sorted_by_value
OrderedDict([('first': 1), ('second': 2), ('third': 3), ('fourth': 4)])
arcseldon picture
2015年12月05日
106

更新:Python3.5を使用した2015年12月5日

受け入れられた回答は役に立ちましたが、このタイプの問題を正確に解決するように設計された、実行可能な最新の代替手段として、標準ライブラリコレクションモジュールからOrderedDictを参照する

from operator import itemgetter
from collections import OrderedDict

x = {1: 2, 3: 4, 4: 3, 2: 1, 0: 0}
sorted_x = OrderedDict(sorted(x.items(), key=itemgetter(1)))
# OrderedDict([(0, 0), (2, 1), (1, 2), (4, 3), (3, 4)])

公式のOrderedDictドキュメントにも非常によく似た例がありますが、sort関数にラムダを使用しています。

# regular unsorted dictionary
d = {'banana': 3, 'apple':4, 'pear': 1, 'orange': 2}

# dictionary sorted by value
OrderedDict(sorted(d.items(), key=lambda t: t[1]))
# OrderedDict([('pear', 1), ('orange', 2), ('banana', 3), ('apple', 4)])
user26294 picture
2009年03月05日
87

ハンクゲイの答えとほとんど同じです:

sorted([(value,key) for (key,value) in mydict.items()])

または、John Fouhyが提案したように、わずかに最適化されています。

sorted((value,key) for (key,value) in mydict.items())
Remi picture
2011年08月30日
76

nametupleを使用すると非常に便利なことがよくあります。 たとえば、キーとして「name」、値として「score」の辞書があり、「score」で並べ替えたいとします。

import collections
Player = collections.namedtuple('Player', 'score name')
d = {'John':5, 'Alex':10, 'Richard': 7}

スコアが最も低いものから順に並べ替えます。

worst = sorted(Player(v,k) for (k,v) in d.items())

最初に最高スコアでソート:

best = sorted([Player(v,k) for (k,v) in d.items()], reverse=True)

これで、の名前とスコアを取得できます。たとえば、次のように非常にPython的に2番目に優れたプレーヤー(index = 1)としましょう。

player = best[1]
player.name
    'Richard'
player.score
    7
Dilettant picture
2016年09月10日
74

Python 3.6以降、組み込みのdictが注文されます

朗報です。したがって、データベースから取得したペアをキーとして一意の文字列IDと値として数値としてマッピングする、OPの元のユースケースは、組み込みのPython v3.6 + dictに挿入順序を尊重する必要があります。

次のようなデータベースクエリから得られた2つの列テーブル式を言うと:

SELECT a_key, a_value FROM a_table ORDER BY a_value;

2つのPythonタプルk_seqとv_seq(数値インデックスで整列され、もちろん同じ長さ)に格納されます。

k_seq = ('foo', 'bar', 'baz')
v_seq = (0, 1, 42)
ordered_map = dict(zip(k_seq, v_seq))

後で次のように出力できるようにします。

for k, v in ordered_map.items():
    print(k, v)

この場合の降伏(新しいPython 3.6以降の組み込みdictの場合!):

foo 0
bar 1
baz 42

vの値ごとに同じ順序で。

Python 3.5を私のマシンにインストールすると、現在次のようになります。

bar 1
foo 0
baz 42

詳細:

Raymond Hettingerによって2012年に提案されたように( 「より高速な反復でよりコンパクトな辞書」という件名のpython-devのメールを参照)、現在(2016年に)VictorStinnerから Python3.6dict「コンパクトで順序付けられたdict」の修正/実装により、キーワードが順序付けられます。組み込みのdictを使用して挿入順序を維持できるようになります。

うまくいけば、これは最初のステップとして薄層のOrderedDictの実装につながるでしょう。 @ JimFasarakis-Hilliardが示したように、将来的にもOrderedDictタイプのユースケースを見る人もいます。 Pythonコミュニティ全体が慎重に調査し、これが時の試練に耐えられるかどうか、そして次のステップはどうなるかを検討すると思います。

次の安定した順序付けによって開かれた可能性を見逃さないように、コーディングの習慣を再考する時が来ました。

  • キーワード引数と
  • (中級)dictストレージ

1つ目は、関数やメソッドの実装でディスパッチが容易になる場合があるためです。

2つ目は、処理パイプラインの中間ストレージとしてdictをより簡単に使用することを推奨するためです。

レイモンドヘッティンガーは親切に「を説明する文書提供のPython 3.6辞書の後ろテック」 -彼のサンフランシスコPythonのミートアップグループ・プレゼンテーション2016-DEC-08から。

また、Stack Overflowの装飾が施された質問と回答のページのかなりの部分がこの情報のバリエーションを受け取り、高品質の回答の多くはバージョンごとの更新も必要になります。

警告エンプター(ただし、以下の更新2017-12-15も参照):

@ajcrが正しく指摘しているように、「この新しい実装の順序を維持する側面は、実装の詳細と見なされるため、信頼すべきではありません。」 ( whatsnew36から)ニットピッキングではありません、引用は少し悲観的にカットされました;-)。 「これは将来変更される可能性がありますが、現在および将来のすべてのPython実装に順序保持セマンティクスを義務付けるように言語仕様を変更する前に、いくつかのリリースでこの新しいdict実装を言語に含めることが望まれます。これもPython 3.5など、ランダムな反復順序がまだ有効な古いバージョンの言語との下位互換性を維持するのに役立ちます。」

したがって、一部の人間の言語(ドイツ語など)と同様に、使用法によって言語が形成され、意志が宣言されました... whatsnew36で

更新2017-12-15:

python-devリストへのメールで、Guido vanRossumは次のように宣言しました。

そうしてください。 「ディクトは挿入順序を維持する」が裁定です。 ありがとう!

そのため、dict挿入順序のバージョン3.6 CPythonの副作用は、言語仕様の一部になりつつあります(実装の詳細だけではありません)。 そのメールスレッドは、議論中にRaymond Hettingerが思い出したように、 collections.OrderedDictいくつかの際立った設計目標も明らかにしました。

jimifiki picture
2010年11月18日
43

私は同じ問題を抱えていました、そして私はそれをこのように解決しました:

WantedOutput = sorted(MyDict, key=lambda x : MyDict[x]) 

(「辞書を並べ替えることができない」と答えた人は質問を読んでいませんでした!実際、「キーで並べ替えることはできますが、値に基づいて並べ替えるにはどうすればよいですか?」ということは、明らかに彼がリストを必要としていることを意味します。値の値に従ってソートされたキー。)

順序が明確に定義されていないことに注意してください(同じ値のキーは、出力リストで任意の順序になります)。