辞書を値でソートするにはどうすればよいですか?
-
03-07-2019 - |
質問
データベースの2つのフィールド(文字列フィールドと数値フィールド)から読み取った値の辞書があります。文字列フィールドは一意であるため、辞書のキーになります。
キーでソートできますが、値に基づいてソートするにはどうすればよいですか
注:ここでStack Overflowの質問を読みました 辞書の値で辞書のリストを並べ替えるにはどうすればよいですか そしておそらく辞書のリストを持つようにコードを変更できますが、辞書のリストが本当に必要ないので、昇順または降順でソートするためのより簡単な解決策があるかどうかを知りたいと思いました。
解決
ディクショナリをソートすることはできません。ソートされたディクショナリの表現を取得するだけです。辞書は本質的に無秩序ですが、リストやタプルなどの他のタイプはそうではありません。そのため、ソートされた値を表すために順序付けられたデータ型が必要です。これは、おそらくタプルのリストになります。
たとえば、
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では、解凍が許可されていないため、 [1] を使用できます
x = {1: 2, 3: 4, 4: 3, 2: 1, 0: 0}
sorted_x = sorted(x.items(), key=lambda kv: kv[1])
辞書として出力する場合は、 collections.OrderedDict
:
import collections
sorted_dict = collections.OrderedDict(sorted_x)
他のヒント
簡単: 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]
「キーで辞書を簡単に並べ替えることができますが、値で並べ替えるにはどうすればよいですか?」 -そして、私はOPがそのような問題に対処しようとしていたと思います。そして解決策は、上記のように、値に基づいてキーのリストの並べ替えを行うことです。
次を使用できます:
sorted(d.items(), key=lambda x: x[1])
これにより、辞書内の各エントリの値で辞書が最小から最大に並べ替えられます。
降順で並べ替えるには、 reverse = True
を追加するだけです:
sorted(d.items(), key=lambda x: x[1], reverse=True)
ディクテーションはソートできませんが、それらからソート済みリストを作成できます。
dict値のソートされたリスト:
sorted(d.values())
値でソートされた(キー、値)ペアのリスト:
from operator import itemgetter
sorted(d.items(), key=itemgetter(1))
最近のPython 2.7には、新しい OrderedDict タイプ。アイテムが追加された順序を記憶します。
>>> 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は通常の辞書のように動作します:
>>> 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)])
更新:Python 3.5を使用した2015年12月5日
受け入れられた回答が有用であるとわかった一方で、 OrderedDict 標準ライブラリ collections モジュールの実行可能な最新の代替-まさにこのタイプの問題を解決するように設計されています。
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 ドキュメントにも非常によく似た例がありますが、ソート関数にラムダを使用しています:
# 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)])
ハンクゲイの回答とほぼ同じ:
sorted([(value,key) for (key,value) in mydict.items()])
またはジョン・フーヒの提案に従ってわずかに最適化:
sorted((value,key) for (key,value) in mydict.items())
多くの場合、 namedtuple を使用すると非常に便利です。 。たとえば、キーとして「名前」、値として「スコア」のディクショナリがあり、「スコア」でソートする場合:
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)
名前とスコアを取得できるようになりました。2番目に優れたプレーヤー(index = 1)が非常にPython的に次のようになっているとします。
player = best[1]
player.name
'Richard'
player.score
7
Python 3.6 では、組み込みのdictが注文されます
朗報ですので、キーとして一意の文字列ID、値として数値を組み込みPython v3.6 + dictにデータベースから取得したペアをマッピングするOPの元のユースケースでは、挿入順序を尊重する必要があります。
次のようなデータベースクエリから得られる2つの列テーブル式を言う場合:
SELECT a_key, a_value FROM a_table ORDER BY a_value;
Pythonの2つのタプル、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+組み込み辞書用!):
foo 0
bar 1
baz 42
vの値ごとに同じ順序で。
Python 3.5の私のマシンへのインストール場所は現在次のとおりです:
bar 1
foo 0
baz 42
詳細:
レイモンド・ヘッティンガーが2012年に提案したとおり(cf. python-devの件名"より高速な反復処理を備えたよりコンパクトな辞書" )、現在(2016年)Victor Stinnerによるpython-devへのメールで件名" Python 3.6 dictはコンパクトになり、プライベートバージョンになります。問題27350 "コンパクトで順序付けられたdict" の修正/実装により、キーワードが順序付けられた" a> Python 3.6では、組み込みのdictを使用して挿入順序を維持できるようになりました!!
うまくいけば、これは最初のステップとして薄層のOrderedDict実装につながるでしょう。 @ JimFasarakis-Hilliardが示したように、将来的にはOrderedDictタイプのユースケースも見られます。 Pythonコミュニティ全体は、これが時の試練に耐えられるかどうか、そして次のステップがどうなるかを注意深く調べると思います。
次の安定した順序付けによって開かれた可能性を見逃さないように、コーディング習慣を再考するとき
- キーワード引数と
- (中間)dictストレージ
最初の方法は、場合によっては関数とメソッドの実装でディスパッチを容易にするためです。
処理パイプラインの中間ストレージとして dict
をより簡単に使用することを推奨する2番目。
Raymond Hettingerは" Python 3.6辞書の裏側の技術" -San Francisco Python Meetup Groupプレゼンテーション2016-DEC-08から。
また、かなりの数のStack Overflowの高い装飾が施された質問と回答のページにはこの情報のバリエーションがあり、多くの高品質の回答にはバージョンごとの更新が必要になります。
警告Emptor(ただし、以下の更新2017-12-15も参照):
@ajcrが正しく注記しているように、"この新しい実装の順序を維持する側面は、実装の詳細と見なされるため、これに依存すべきではありません。" ( whatsnew36 から)選ばれていない、しかし引用は少し悲観的にカットされました;-)。 "として継続します(これは将来変更される可能性がありますが、言語仕様を変更して現在および将来のすべてのPython実装の順序を維持するセマンティクスを義務付ける前に、この新しいdict実装をいくつかのリリースで言語に実装することが望まれます。ランダム反復順序がまだ有効な古いバージョンの言語との互換性(Python 3.5など)。"
一部の人間の言語(ドイツ語など)のように、使用法によって言語が形作られ、意志が宣言されました...
同じ問題がありましたが、次のように解決しました: (「辞書をソートすることはできません」と答えた人は質問を読みませんでした!実際、「キーでソートできますが、値に基づいてソートするにはどうすればよいですか?」キーの値の値に基づいてソートされたキーのリストが必要であること。) 順序が適切に定義されていないことに注意してください(同じ値を持つキーは、出力リストで任意の順序になります)。WantedOutput = sorted(MyDict, key=lambda x : MyDict[x])
Python 2.7では、次のようにします。
from collections import OrderedDict
# regular unsorted dictionary
d = {'banana': 3, 'apple':4, 'pear': 1, 'orange': 2}
# dictionary sorted by key
OrderedDict(sorted(d.items(), key=lambda t: t[0]))
OrderedDict([('apple', 4), ('banana', 3), ('orange', 2), ('pear', 1)])
# dictionary sorted by value
OrderedDict(sorted(d.items(), key=lambda t: t[1]))
OrderedDict([('pear', 1), ('orange', 2), ('banana', 3), ('apple', 4)])
からのコピーペースト: http://docs.python.org/ dev / library / collections.html#ordereddict-examples-and-recipes
楽しむ;-)
これはコードです:
import operator
origin_list = [
{"name": "foo", "rank": 0, "rofl": 20000},
{"name": "Silly", "rank": 15, "rofl": 1000},
{"name": "Baa", "rank": 300, "rofl": 20},
{"name": "Zoo", "rank": 10, "rofl": 200},
{"name": "Penguin", "rank": -1, "rofl": 10000}
]
print ">> Original >>"
for foo in origin_list:
print foo
print "\n>> Rofl sort >>"
for foo in sorted(origin_list, key=operator.itemgetter("rofl")):
print foo
print "\n>> Rank sort >>"
for foo in sorted(origin_list, key=operator.itemgetter("rank")):
print foo
結果は次のとおりです。
オリジナル
{'name': 'foo', 'rank': 0, 'rofl': 20000}
{'name': 'Silly', 'rank': 15, 'rofl': 1000}
{'name': 'Baa', 'rank': 300, 'rofl': 20}
{'name': 'Zoo', 'rank': 10, 'rofl': 200}
{'name': 'Penguin', 'rank': -1, 'rofl': 10000}
Rofl
{'name': 'Baa', 'rank': 300, 'rofl': 20}
{'name': 'Zoo', 'rank': 10, 'rofl': 200}
{'name': 'Silly', 'rank': 15, 'rofl': 1000}
{'name': 'Penguin', 'rank': -1, 'rofl': 10000}
{'name': 'foo', 'rank': 0, 'rofl': 20000}
ランク
{'name': 'Penguin', 'rank': -1, 'rofl': 10000}
{'name': 'foo', 'rank': 0, 'rofl': 20000}
{'name': 'Zoo', 'rank': 10, 'rofl': 200}
{'name': 'Silly', 'rank': 15, 'rofl': 1000}
{'name': 'Baa', 'rank': 300, 'rofl': 20}
次のアプローチを試してください。次のデータを使用してmydictという辞書を定義します。
mydict = {'carl':40,
'alan':2,
'bob':1,
'danny':3}
キーで辞書をソートしたい場合、次のようなことができます:
for key in sorted(mydict.iterkeys()):
print "%s: %s" % (key, mydict[key])
これにより、次の出力が返されます。
alan: 2
bob: 1
carl: 40
danny: 3
一方で、値で辞書をソートしたい場合(質問で尋ねられているように)、次のことができます:
for key, value in sorted(mydict.iteritems(), key=lambda (k,v): (v,k)):
print "%s: %s" % (key, value)
このコマンドの結果(値でディクショナリを並べ替える)は、次を返します。
bob: 1
alan: 2
danny: 3
carl: 40
「反転インデックス」を作成することもできます
from collections import defaultdict
inverse= defaultdict( list )
for k, v in originalDict.items():
inverse[v].append( k )
これで、インバースに値が追加されました。各値には適用可能なキーのリストがあります。
for k in sorted(inverse):
print k, inverse[k]
collections.Counter を使用できます。注、これは数値と非数値の両方で機能します。
>>> x = {1: 2, 3: 4, 4:3, 2:1, 0:0}
>>> from collections import Counter
>>> #To sort in reverse order
>>> Counter(x).most_common()
[(3, 4), (4, 3), (1, 2), (2, 1), (0, 0)]
>>> #To sort in ascending order
>>> Counter(x).most_common()[::-1]
[(0, 0), (2, 1), (1, 2), (4, 3), (3, 4)]
>>> #To get a dictionary sorted by values
>>> from collections import OrderedDict
>>> OrderedDict(Counter(x).most_common()[::-1])
OrderedDict([(0, 0), (2, 1), (1, 2), (4, 3), (3, 4)])
Python 3.6以降、 dict
オブジェクトは挿入順に並べられます。公式にはPython 3.7の仕様にあります。
>>> words = {"python": 2, "blah": 4, "alice": 3}
>>> dict(sorted(words.items(), key=lambda x: x[1]))
{'python': 2, 'alice': 3, 'blah': 4}
それ以前は、 OrderedDict
を使用する必要がありました。
バージョン3.7で変更:辞書の順序は必ず挿入されます 注文。この動作は、3.6からのCPythonの実装の詳細でした。
from django.utils.datastructures import SortedDict
def sortedDictByKey(self,data):
"""Sorted dictionary order by key"""
sortedDict = SortedDict()
if data:
if isinstance(data, dict):
sortedKey = sorted(data.keys())
for k in sortedKey:
sortedDict[k] = data[k]
return sortedDict
キーに渡すことができるカスタム関数を使用することもできます。
def dict_val(x):
return x[1]
x = {1: 2, 3: 4, 4: 3, 2: 1, 0: 0}
sorted_x = sorted(x.items(), key=dict_val)
Dilettantが指摘したように、Python 3.6は注文を保持します!反復可能(タプル、リスト、辞書)のソートを容易にする関数を書いたと思います。後者の場合、キーまたは値でソートでき、数値比較を考慮することができます。 > = 3.6のみ!
たとえば、文字列とint、sorted()は失敗します。もちろん、str()で文字列の比較を強制できます。ただし、場合によっては、 12
が 20
より小さい実際の数値比較を行います(文字列比較の場合はそうではありません)。そこで、次のことを思いつきました。明示的な数値比較が必要な場合は、フラグ num_as_num
を使用できます。このフラグは、すべての値を浮動小数点数に変換することにより、明示的な数値ソートを試行します。それが成功した場合、数値の並べ替えを行います。それ以外の場合は、文字列比較に頼ります。
改善のためのコメントまたはプッシュリクエストようこそ。
def sort_iterable(iterable, sort_on=None, reverse=False, num_as_num=False):
def _sort(i):
# sort by 0 = keys, 1 values, None for lists and tuples
try:
if num_as_num:
if i is None:
_sorted = sorted(iterable, key=lambda v: float(v), reverse=reverse)
else:
_sorted = dict(sorted(iterable.items(), key=lambda v: float(v[i]), reverse=reverse))
else:
raise TypeError
except (TypeError, ValueError):
if i is None:
_sorted = sorted(iterable, key=lambda v: str(v), reverse=reverse)
else:
_sorted = dict(sorted(iterable.items(), key=lambda v: str(v[i]), reverse=reverse))
return _sorted
if isinstance(iterable, list):
sorted_list = _sort(None)
return sorted_list
elif isinstance(iterable, tuple):
sorted_list = tuple(_sort(None))
return sorted_list
elif isinstance(iterable, dict):
if sort_on == 'keys':
sorted_dict = _sort(0)
return sorted_dict
elif sort_on == 'values':
sorted_dict = _sort(1)
return sorted_dict
elif sort_on is not None:
raise ValueError(f"Unexpected value {sort_on} for sort_on. When sorting a dict, use key or values")
else:
raise TypeError(f"Unexpected type {type(iterable)} for iterable. Expected a list, tuple, or dict")
dでzipを使用したソリューションです。 values()
および d.keys()
。このリンクの下の数行(ディクショナリビューオブジェクト上)は次のとおりです。
これにより、zip()を使用して(値、キー)ペアを作成できます。pairs= zip(d.values()、d.keys())。
したがって、次のことができます。
d = {'key1': 874.7, 'key2': 5, 'key3': 8.1}
d_sorted = sorted(zip(d.values(), d.keys()))
print d_sorted
# prints: [(5, 'key2'), (8.1, 'key3'), (874.7, 'key1')]
dicts の ValueSortedDict を使用:
from dicts.sorteddict import ValueSortedDict
d = {1: 2, 3: 4, 4:3, 2:1, 0:0}
sorted_dict = ValueSortedDict(d)
print sorted_dict.items()
[(0, 0), (2, 1), (1, 2), (4, 3), (3, 4)]
dictを反復処理し、値で降順に並べ替えます:
$ python --version
Python 3.2.2
$ cat sort_dict_by_val_desc.py
dictionary = dict(siis = 1, sana = 2, joka = 3, tuli = 4, aina = 5)
for word in sorted(dictionary, key=dictionary.get, reverse=True):
print(word, dictionary[word])
$ python sort_dict_by_val_desc.py
aina 5
tuli 4
joka 3
sana 2
siis 1
値が整数で、Python 2.7以降を使用している場合は、 dict
ではなく、 collections.Counter
。 most_common
メソッドは、値でソートされたすべてのアイテムを提供します。
もちろん、通常のPython辞書は元の順序を保持しないため、 OrderedDict
を使用する必要があることを忘れないでください。
from collections import OrderedDict
a = OrderedDict(sorted(originalDict.items(), key=lambda x: x[1]))
Python 2.7以降を使用していない場合は、ジェネレーター関数の値を反復処理するのが最善です。 (2.4および2.6には OrderedDict
がありますこちら、ただし
a)どれだけうまく機能するかわかりません
and
b)もちろん、ダウンロードしてインストールする必要があります。管理者アクセス権がない場合、このオプションが使用できないのではないかと思います。)
def gen(originalDict):
for x, y in sorted(zip(originalDict.keys(), originalDict.values()), key=lambda z: z[1]):
yield (x, y)
#Yields as a tuple with (key, value). You can iterate with conditional clauses to get what you want.
for bleh, meh in gen(myDict):
if bleh == "foo":
print(myDict[bleh])
すべての値を印刷することもできます
for bleh, meh in gen(myDict):
print(bleh, meh)
Python 3.0以降を使用しない場合は、印刷後に括弧を忘れずに削除してください
これは3.1.xで機能します:
import operator
slovar_sorted=sorted(slovar.items(), key=operator.itemgetter(1), reverse=True)
print(slovar_sorted)
完全を期すために、 heapq を使用してソリューションを投稿しています。このメソッドは、数値と非数値の両方で機能することに注意してください
>>> x = {1: 2, 3: 4, 4:3, 2:1, 0:0}
>>> x_items = x.items()
>>> heapq.heapify(x_items)
>>> #To sort in reverse order
>>> heapq.nlargest(len(x_items),x_items, operator.itemgetter(1))
[(3, 4), (4, 3), (1, 2), (2, 1), (0, 0)]
>>> #To sort in ascending order
>>> heapq.nsmallest(len(x_items),x_items, operator.itemgetter(1))
[(0, 0), (2, 1), (1, 2), (4, 3), (3, 4)]
Python for Everybody から関連スキルを習得した。
辞書のソートに役立つ一時リストを使用できます:
#Assume dictionary to be:
d = {'apple': 500.1, 'banana': 1500.2, 'orange': 1.0, 'pineapple': 789.0}
# create a temporary list
tmp = []
# iterate through the dictionary and append each tuple into the temporary list
for key, value in d.items():
tmptuple = (value, key)
tmp.append(tmptuple)
# sort the list in ascending order
tmp = sorted(tmp)
print (tmp)
リストを降順で並べ替える場合は、元の並べ替え行を次のように変更します。
tmp = sorted(tmp, reverse=True)
リストの内包表記を使用すると、1つのライナーは次のようになります。
#Assuming the dictionary looks like
d = {'apple': 500.1, 'banana': 1500.2, 'orange': 1.0, 'pineapple': 789.0}
#One liner for sorting in ascending order
print (sorted([(v, k) for k, v in d.items()]))
#One liner for sorting in descending order
print (sorted([(v, k) for k, v in d.items()], reverse=True))
サンプル出力:
#Asending order
[(1.0, 'orange'), (500.1, 'apple'), (789.0, 'pineapple'), (1500.2, 'banana')]
#Descending order
[(1500.2, 'banana'), (789.0, 'pineapple'), (500.1, 'apple'), (1.0, 'orange')]
months = {"January": 31, "February": 28, "March": 31, "April": 30, "May": 31,
"June": 30, "July": 31, "August": 31, "September": 30, "October": 31,
"November": 30, "December": 31}
def mykey(t):
""" Customize your sorting logic using this function. The parameter to
this function is a tuple. Comment/uncomment the return statements to test
different logics.
"""
return t[1] # sort by number of days in the month
#return t[1], t[0] # sort by number of days, then by month name
#return len(t[0]) # sort by length of month name
#return t[0][-1] # sort by last character of month name
# Since a dictionary can't be sorted by value, what you can do is to convert
# it into a list of tuples with tuple length 2.
# You can then do custom sorts by passing your own function to sorted().
months_as_list = sorted(months.items(), key=mykey, reverse=False)
for month in months_as_list:
print month