代码之家  ›  专栏  ›  技术社区  ›  Gern Blanston

如何按值对词典排序?

  •  3256
  • Gern Blanston  · 技术社区  · 16 年前

    我有一个从数据库中的两个字段读取的值字典:字符串字段和数字字段。字符串字段是唯一的,因此它是字典的键。

    我可以按键排序,但如何根据值排序?

    How do I sort a list of dictionaries by a value of the dictionary? 也许我可以修改我的代码,让它有一个字典列表,但由于我并不需要字典列表,我想知道是否有一个更简单的解决方案,可以按升序或降序排序。

    41 回复  |  直到 6 年前
        1
  •  5979
  •   wjandrea senderle    4 年前

    Python 3.7+或CPython 3.6

    it's an implementation detail .

    >>> 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}
    

    不可能对字典进行排序,只能获得已排序字典的表示形式。字典本质上是无序的,但其他类型(如列表和元组)则不是。因此,您需要一个有序的数据类型来表示已排序的值,这将是一个列表,可能是一个元组列表。

    例如,

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

    sorted_x 将是按每个元组中的第二个元素排序的元组列表。 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))
    

    unpacking is not allowed 我们可以使用

    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)
    
        2
  •  1450
  •   Boris Verkhovskiy Brian Clapper    5 年前

    简单到: sorted(dict1, key=dict1.get)

    Code golf: Word frequency chart )简而言之,问题是这样的:给定一个文本,计算每个单词出现的频率,并显示一个按频率递减排序的最热门单词列表。

    如果以单词作为关键字,以每个单词的出现次数作为值来构建词典,则此处简化为:

    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])
    

        3
  •  1003
  •   Suresh2692 Mark    5 年前

    您可以使用:

    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)]
    
        4
  •  253
  •   Roberto Bonvallet    10 年前

    dict值的排序列表:

    sorted(d.values())
    

    按值排序的(键、值)对列表:

    from operator import itemgetter
    sorted(d.items(), key=itemgetter(1))
    
        5
  •  174
  •   Peter Mortensen icecrime    11 年前

    在最近的Python2.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的行为与普通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)])
    
        6
  •  112
  •   arcseldon    9 年前

    更新:2015年12月5日使用Python 3.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)])
    

    有序的 文档也提供了一个非常类似的示例,但使用lambda作为排序函数:

    # 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)])
    
        7
  •  102
  •   Justin Batch user26294    6 年前

    差不多和 Hank Gay's answer :

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

    或者按照John Fouhy的建议稍微优化:

    sorted((value,key) for (key,value) in mydict.items())
    
        8
  •  81
  •   vallentin Remi    8 年前

    它通常使用起来非常方便 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)
    

    player = best[1]
    player.name
        'Richard'
    player.score
        7
    
        9
  •  81
  •   Dilettant    7 年前

    截至 Python 3.6 将订购内置dict

    好消息是,OP最初的用例是将从数据库中检索到的对映射到内置Python v3.6+dict中,该数据库使用唯一的字符串ID作为键,数字值作为值,现在应该遵循插入顺序。

    SELECT a_key, a_value FROM a_table ORDER BY a_value;
    

    将存储在两个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
    

    在我的机器上安装的Python 3.5中,当前会产生:

    bar 1
    foo 0
    baz 42
    

    细节:

    正如Raymond Hettinger在2012年提出的(参见主题为python开发的邮件) "More compact dictionaries with faster iteration" "Python 3.6 dict becomes compact and gets a private version; and keywords become ordered" "Compact and ordered dict" 在Python3.6中,我们现在可以使用内置dict来维护插入顺序!!

    希望这将导致作为第一步的薄层有序的ICT实现。正如@JimFasarakis Hilliard所指出的,一些人在将来也会看到OrderedDict类型的用例。我认为整个Python社区都会仔细检查,这是否经得起时间的考验,以及接下来的步骤是什么。

    • 关键字参数和
    • (中间)dict存储

    第二,因为它鼓励更容易地使用 dict 作为加工管道中的中间存储。

    雷蒙德·赫廷格(Raymond Hettinger)好心地提供了文件,解释了 The Tech Behind Python 3.6 Dictionaries 从他的旧金山Python MeTup集团介绍2016DEC-08。

    也许相当多的堆栈溢出高装饰的问题和答案页面将收到这些信息的变体,许多高质量的答案也需要每个版本的更新。

    whatsnew36 但是 引用被删去了一点悲观;-)。它继续是“(这在将来可能会发生变化,但在将语言规范更改为所有当前和未来Python实现的命令保留语义之前,希望在一些版本中使用这种新的dict实现;这也有助于保持与旧版本的语言的向后兼容性,其中随机迭代离子顺序仍然有效,例如Python 3.5)。”

    因此,就像在某些人类语言(如德语)中一样,用法塑造了语言,而意志现在已经被宣布。。。在里面 什么新闻36

    更新2017-12-15:

    mail to the python-dev list

    就这样吧。“Dict保持插入顺序”是裁决。谢谢

    因此,dict插入顺序的3.6版CPython副作用现在已经成为语言规范的一部分(不再只是一个实现细节)。该邮件线程还显示了一些独特的设计目标 collections.OrderedDict 正如Raymond Hettinger在讨论中提醒的那样。

        10
  •  47
  •   Peter Mortensen icecrime    7 年前

    我也有同样的问题,我这样解决:

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

    (回答“不可能对dict排序”的人没有读过这个问题!事实上,“我可以按键排序,但如何根据值排序?”显然意味着他想要一个按键值排序的键列表。)

    请注意,顺序没有很好地定义(具有相同值的键将在输出列表中以任意顺序排列)。

        11
  •  45
  •   Georgy rassa45    6 年前

    如果值是数字,也可以使用 Counter collections .

    from collections import Counter
    
    x = {'hello': 1, 'python': 5, 'world': 3}
    c = Counter(x)
    print(c.most_common())
    
    >> [('python', 5), ('world', 3), ('hello', 1)]    
    
        12
  •  38
  •   sweetdream    11 年前

    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

    享受;-)

        13
  •  29
  •   icedwater PedroMorgan    9 年前

    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}
    

    爆笑

    {'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}
    
        14
  •  28
  •   Peter Mortensen icecrime    7 年前

    尝试以下方法。让我们用以下数据定义一个名为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
    
        15
  •  26
  •   Maxime Chéramy    6 年前

    dict 对象现在按插入顺序排序。这是Python3.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 documentation

    在版本3.7中更改:保证插入字典顺序 顺序此行为是3.6中CPython的实现细节。

        16
  •  24
  •   S.Lott    16 年前

    您还可以创建“反向索引”

    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]
    
        17
  •  22
  •   Peter Mortensen icecrime    11 年前

    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)])
    
        18
  •  17
  •   Georgy rassa45    6 年前

    您还可以使用可以传递给键的自定义函数。

    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)
    
        19
  •  16
  •   malthe    10 年前

    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() 然后,您将按值的排序顺序进行迭代。

    它是使用 skip list

        20
  •  14
  •   Argun    14 年前
    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
    
        21
  •  13
  •   Georgy rassa45    6 年前

    OrderedDict 因为常规Python字典不保持原始顺序。

    from collections import OrderedDict
    a = OrderedDict(sorted(originalDict.items(), key=lambda x: x[1]))
    

    如果您没有Python2.7或更高版本,那么最好是迭代生成器函数中的值。(有一个 here 但是


    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或更高版本,请记住在打印后删除括号

        22
  •  13
  •   Bram Vanroy    4 年前

    As pointed out by Dilettant ,Python3.6现在将 遵守秩序 仅适用于>=3.6!

    当您尝试在包含字符串和整数的iterable上使用sorted时,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")
    
        23
  •  12
  •   Scott    9 年前

    这里有一个使用zip的解决方案 d.values() and d.keys() . 此链接下面的几行(在Dictionary view对象上)是:

    因此,我们可以做到以下几点:

    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')]
    
        24
  •  9
  •   ponty    13 年前

    从…起 dicts :

    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)]
    
        25
  •  9
  •   mcgag    7 年前

    刚从学校学到相关技能 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)
    

    使用列表理解,一行是:

    #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')]
    
        26
  •  8
  •   juhoh    13 年前

    迭代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
    
        27
  •  7
  •   ï¾ ï¾ ï¾    13 年前

    collections.Counter 而不是 dict . 这个 most_common 方法将为您提供按值排序的所有项。

        28
  •  7
  •   Nathaniel Ford iFail    12 年前

    import operator
    slovar_sorted=sorted(slovar.items(), key=operator.itemgetter(1), reverse=True)
    print(slovar_sorted)
    
        29
  •  7
  •   Abhijit    12 年前

    为了完整起见,我发布了一个使用 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)]
    
        30
  •  6
  •   lessthanl0l    11 年前
    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