【问题标题】:How do I sort a complex dictionary by a key, which resides deep the dictionary?如何按位于字典深处的键对复杂字典进行排序?
【发布时间】:2014-08-25 20:07:32
【问题描述】:

我有一本这样结构的字典:

{
  "Mark":
  {
    "surname":"Johnson",
    "tags":
    [
      {
        "name":"Salary",
        "value":"5"
      },
      {
        "name":"Car manufacturer",
        "value":"Volvo"
      }
    ]
  },
  "John":
  {
    "surname":"Doe",
    "tags":
    [
      {
        "name":"Salary",
        "value":"10"
      },
      {
        "name":"Car manufacturer",
        "value":"Daewoo"
      }
    ]
  }
}

我想按名称为“汽车制造商”的标签值对该字典进行排序,以获得如下结果:

{
  "Volvo": 
  {
    [
     "Mark":{...},...
    ]
  },
  "Daewoo":
  {
    ["John":{...}]
  }
}

有没有办法让它尽可能优雅?我可以通过创建几个嵌套循环来做到这一点(下面的示例),但它看起来很难看,而且可能效率不高。

cars = {}
for person in persons:
  for tag in person['tags']:
    if tag['name'] == 'Car manufacturer'
      cars[tag['value']].append(item)

【问题讨论】:

  • 这和你得到的一样好;这很尴尬,因为起始数据结构不是很好。
  • 您不需要排序。您需要对数据进行某种转置

标签: python list sorting dictionary


【解决方案1】:

老实说,您的起始数据结构设计得很糟糕。它可能在小范围内起作用,但是随着您的进步并且您的项目“字典”变大,您已经可以看到它很快就会变得不堪重负。尝试创建一个类,并创建结构的不同实例。例如:

class Employees():
    def __init__(self):
        self.surname = ''
        self.salary = 0
        self.car_man = []  # if in case you want to add more than one car use a list type or just use string if you plan on keeping this a single value

您可以从这里创建实例,并且可以更轻松地跟踪它们。您甚至可以将这些单独的实例添加到字典本身并对其进行排序。

前:

 Mark = Employees()
 Mark.surname = 'Johnson'
 Mark.salary = 5
 Mark.car_man = 'Volvo'

 John = Employees()
 John.surname = "Doe"
 John.salary = 10
 John.car_man = Daewoo

根据需要对它们中的任意数量执行这些操作,然后您可以将这些实例添加到字典中并能够更轻松地对它们进行排序。

将它们添加到字典中很简单:

my_dict = {}
my_dict[#key] = # your instance

【讨论】:

  • 或者Employee 可以有一个列表属性cars,其中包含Car 对象。
  • 是的,我不是 OP 希望他的数据真正结构化的方式,但希望这会引导他找到他想要的。
  • 不幸的是,我对初始结构无能为力。猜猜我必须尝试您的解决方案并比较性能。
【解决方案2】:

字典理解 - 虽然我倾向于回避它 - 如果你是那种人,可能会使你的代码更具可读性。

import pprint
pp = pprint.PrettyPrinter(indent=3)

cars = {}
for person in persons:
  for tag in persons[person]['tags']:
    if tag['name'] == 'Car manufacturer':
      if tag['value'] in cars:
          cars[tag['value']][person] = persons[person]
      else:
          cars[tag['value']] = {person:persons[person]}

pp.pprint(cars)

cars = {tag['value']:{person:persons[person]} for person in persons for tag in persons[person]['tags'] if tag['name'] == 'Car manufacturer'}
pp.pprint(cars)

我同意其他人对您数据结构的看法。更不用说您提供的代码没有按照提供的方式运行,因此我们很难准确推断出您想要什么。

我怀疑有人会想出比你更有效的答案。

【讨论】:

    【解决方案3】:

    可能不是最有效的,因为它每次都需要生成字典,但你的标签列表会更好地表示为字典而不是带有“名称”和“值”的字典列表。

    sorted(
        d.items(),
        key=lambda x: dict(
            (kv["name"], kv["value"])
            for kv in x[1]["tags"]
        )["Car manufacturer"]
    )
    

    【讨论】:

      【解决方案4】:

      根据你自己的回答:

      cars = {}
      for name in persons:
        for tag in persons[name]['tags']:
          if tag['name'] == 'Car manufacturer':
            cars.setdefault(tag['value'],{})[name] = persons[name]
            break
      

      制作:

      {'Daewoo': {'John': {'surname': 'Doe',
                           'tags': [{'name': 'Salary', 'value': '10'},
                                    {'name': 'Car manufacturer',
                                     'value': 'Daewoo'}]}},
       'Volvo': {'Mark': {'surname': 'Johnson',
                          'tags': [{'name': 'Salary', 'value': '5'},
                                   {'name': 'Car manufacturer', 'value': 'Volvo'}]}}
      
      }
      

      不是很性感,但考虑到您的数据结构,可能相当高效。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2013-03-14
        • 1970-01-01
        • 2012-02-18
        • 1970-01-01
        • 2021-06-28
        • 2019-01-30
        相关资源
        最近更新 更多