質問

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

キーでソートできますが、値に基づいてソートするにはどうすればよいですか

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

他のヒント

簡単: 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]) 

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

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

これはコードです:

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}

値が数値の場合、 Counter コレクションから。

from collections import Counter

x = {'hello': 1, 'python': 5, 'world': 3}
c = Counter(x)
print(c.most_common())

>> [('python', 5), ('world', 3), ('hello', 1)]    

次のアプローチを試してください。次のデータを使用して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 を使用する必要がありました。

Python 3.7のドキュメントの説明:

  

バージョン3.7で変更:辞書の順序は必ず挿入されます   注文。この動作は、3.6からのCPythonの実装の詳細でした。

skip dict を使用できます。これは、値によって永続的にソートされる辞書です。

>>> data = {1: 2, 3: 4, 4: 3, 2: 1, 0: 0}
>>> SkipDict(data)
{0: 0.0, 2: 1.0, 1: 2.0, 4: 3.0, 3: 4.0}

keys() values()、または items()を使用する場合、値でソートされた順に反復します。

スキップリストデータ構造を使用して実装されています。

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
ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top