简体   繁体   English

python字典按列表排序

[英]python dictionary sorted by list

I have a list 我有一个清单

category = ['Toy','Cloth','Food','Auto']

I also have a dictionary (where first A, B, C... are item names, first element in each list is category and the second is the price. 我还有一本字典(其中第一个A,B,C ...是商品名称,每个列表中的第一个元素是类别,第二个是价格。

inventory = {'A':['Food', 5], 'B':['Food', 6], 
          'C':['Auto', 5], 'D':['Cloth', 14], 
           'E':['Toy',19], 'F':['Cloth', 13], 'G':['Toy',20], 'H':['Toy',11]}

I would like this to be sorted first by the order of the category in the list, then secondarily, I would like them to be ordered by the price (while category order maintained) such that the result looks like this... 我希望首先按列表中类别的顺序对其进行排序,然后其次,我希望按价格(同时保持类别顺序)对它们进行排序,以使结果看起来像这样……

inventory_sorted = {'G':['Toy',20],'E':['Toy',19], 'H':['Toy',11], 'D':['Cloth', 14], 
                    'F':['Cloth', 13], 'B':['Food', 6],'A':['Food', 5],'C':['Auto', 5],}

Could you please offer me two step process where first is about sorting by the list's category and the second is about sorting (inversely) by the price with the category sorting preserved. 您能否为我提供两步过程,第一步是按列表的类别排序,第二步是按价格排序(反之)并保留类别排序。 If you are using Lambda, please offer me a bit of narrative so that I could understand better. 如果您使用的是Lambda,请提供一些叙述,以便我更好地理解。 I am new to Lamda expressions. 我是Lamda表达式的新手。 Thank you so much 非常感谢

You cannot sort a Python dict object as they are not ordered. 您无法对Python dict对象排序,因为它们没有顺序。 At most, you can produce a sorted sequence of (key-value) pairs. 最多可以产生(键-值)对的排序序列。 You could then feed those pairs to a collections.OrderedDict() object if you want to have a mapping that includes the order. 然后,如果您要具有包含订单的映射,则可以将这些对提供给collections.OrderedDict()对象

Convert your category order to a mapping to get an order, then use that in a sort key together with the price. category订单转换为映射以获取订单,然后将其与价格一起用于排序键。 Since you want your prices sorted in descending order, you need to return the negative price: 由于您希望价格按降序排列,因此需要返回价格:

cat_order = {cat: i for i, cat in enumerate(category)}
inventory_sorted = sorted(inventory.items(),
                          key=lambda i: (cat_order[i[1][0]], -i[1][1]))

The i argument is passed each key-value pair; i参数会传递给每个键值对; i[1] is then the value, and i[1][0] the category, i[1][1] the price. 然后, i[1]是值, i[1][0]是类别, i[1][1]是价格。

This produces key-value pairs in the specified order: 这将按指定顺序生成键值对:

>>> category = ['Toy','Cloth','Food','Auto']
>>> inventory = {'A':['Food', 5], 'B':['Food', 6], 
...           'C':['Auto', 5], 'D':['Cloth', 14], 
...            'E':['Toy',19], 'F':['Cloth', 13], 'G':['Toy',20], 'H':['Toy',11]}
>>> cat_order = {cat: i for i, cat in enumerate(category)}
>>> sorted(inventory.items(), key=lambda i: (cat_order[i[1][0]], -i[1][1]))
[('G', ['Toy', 20]), ('E', ['Toy', 19]), ('H', ['Toy', 11]), ('D', ['Cloth', 14]), ('F', ['Cloth', 13]), ('B', ['Food', 6]), ('A', ['Food', 5]), ('C', ['Auto', 5])]
>>> from pprint import pprint
>>> pprint(_)
[('G', ['Toy', 20]),
 ('E', ['Toy', 19]),
 ('H', ['Toy', 11]),
 ('D', ['Cloth', 14]),
 ('F', ['Cloth', 13]),
 ('B', ['Food', 6]),
 ('A', ['Food', 5]),
 ('C', ['Auto', 5])]

An OrderedDict() object directly accepts this sequence: OrderedDict()对象直接接受以下序列:

>>> from collections import OrderedDict
>>> OrderedDict(sorted(inventory.items(), key=lambda i: (cat_order[i[1][0]], -i[1][1])))
OrderedDict([('G', ['Toy', 20]), ('E', ['Toy', 19]), ('H', ['Toy', 11]), ('D', ['Cloth', 14]), ('F', ['Cloth', 13]), ('B', ['Food', 6]), ('A', ['Food', 5]), ('C', ['Auto', 5])])

You can kind of get this with the following: 您可以通过以下方法获得此信息:

sorted(inventory.items(), key=lambda t: category.index(t[1][0]))

This works because: 之所以有效,是因为:

  • inventory.items() turns your dict into a list of tuples, which can retain an order inventory.items()将您的字典变成元组列表,可以保留订单
  • The key function orders based on where t[1][0] appears in your category list, and key功能的排序基于category列表中t[1][0]出现的位置,以及
  • t will be something like ('G', ('Toy', 20)) so t[1] is ('Toy', 20) and t[1][0] is 'Toy' . t将类似于('G', ('Toy', 20))因此t[1]('Toy', 20)t[1][0]'Toy'

But you cannot go back to a standard dict from this (even though it would be very easy) because you would lose your ordering again, rendering the sort pointless. 但是您不能从中返回标准dict (即使很简单),因为您将再次失去订单,使排序毫无意义。 So you will either have to work with the data in this format, or use something like collections.OrderedDict as already mentioned. 因此,您将不得不使用这种格式的数据,或者使用如上所述的collections.OrderedDict东西。

Another completely different way of doing this, which is rather powerful, is to 执行此操作的另一种完全不同的方法(功能非常强大)是:

  1. use the python class to make the data structure, 使用python类制作数据结构,
  2. store the data in a list 将数据存储在列表中
  3. sort the list with key=attrgetter('variable') 使用key = attrgetter('variable')对列表进行排序

Here's a snippet of example code: 这是示例代码的片段:

class Item:
    def __init__(self,label,category,number):
        self.label = label
        self.category = category
        self.number = number
    def __repr__(self):
        return "Item(%s,%s,%d)"%(self.label,self.category,self.number)
    def __str__(self):
        return "%s: %s,%d"%(self.label,self.category,self.number)

inventory = []
inventory.append(Item("A","Food",5))
inventory.append(Item("B","Food",6))
inventory.append(Item("C","Auto",5))
inventory.append(Item("D","Cloth",14))
inventory.append(Item("E","Toy",19))
inventory.append(Item("F","Cloth",13))
inventory.append(Item("G","Toy",20))
inventory.append(Item("H","Toy",11))

inventory.sort(key=attrgetter('number'),reverse=True)
inventory.sort(key=attrgetter('category'))

The advantage of this, is that the sort is designed to maintain the order from the previous sort, so calling it twice (as I've done above) allows you to sort it by category primarily, but sort it by number secondarily. 这样做的好处是,排序的目的是保持上一个排序的顺序,因此调用它两次(如我上面所做的那样)可以使您首先按类别对它进行排序,但按数字对它进行排序。 You could do this for as many sort keys as you want. 您可以根据需要为任意多个排序键执行此操作。

You can also add whatever other information you want to your Items. 您还可以将所需的任何其他信息添加到项目中。

categories = ['Toy','Cloth','Food','Auto']

inventory = {'A':['Food', 5], 'B':['Food', 6], 
          'C':['Auto', 5], 'D':['Cloth', 14], 
           'E':['Toy',19], 'F':['Cloth', 13], 'G':['Toy',20], 'H':['Toy',11]}

from collections import OrderedDict

inventory_sorted = OrderedDict()

for category in categories:
    same_category = [(key, num) for key, (cat, num) in inventory.items() if cat == category] 

    for (key, num) in sorted(same_category, key=lambda (_, num): num, reverse=True):
        inventory_sorted[key] = [category, num]

for key, value in inventory_sorted.items():
    print key, value

Since dictionaries are unordered we will be using OrderedDict to achieve your goal. 由于dictionaries是无序的,我们将使用OrderedDict实现您的目标。

How it works: 这个怎么运作:

same_category is a simple list comprehension which filters items if they are the same category as the current loop category, it will form a list consisting of tuples of (key, num) pairs. same_category是一个简单的列表same_category ,如果与当前循环类别属于同一类别,则过滤它们,它将形成一个列表,该列表由(键,数字)对的元组组成。

then we sort this new list using the number, the line which does this is key=lambda (_, num): num , this unpacks the tuple, discards the key using _ , and sort by the num , we reverse it so it shows high numbers first. 然后,我们使用数字对这个新列表进行排序,执行此操作的行是key=lambda (_, num): num ,这将拆开元组,使用_丢弃键,然后按num排序,将其反转,从而显示高数字优先。

then we add each of those [category, num] pairs to to the OrderedDict inventory_sorted in the key . 然后我们添加的每个的那些[category, num]对向OrderedDict inventory_sortedkey

Result: 结果:

G ['Toy', 20]
E ['Toy', 19]
H ['Toy', 11]
D ['Cloth', 14]
F ['Cloth', 13]
B ['Food', 6]
A ['Food', 5]
C ['Auto', 5]

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM