【问题标题】:Is there a way to sort a dictionary from the outside in有没有办法从外部对字典进行排序
【发布时间】:2020-12-09 04:02:52
【问题描述】:

我正在尝试创建一个事件管理器,其中字典存储这样的事件

my_dict = {'2020': 
                 {'9': {'8': ['School ']}, 
                  '11': {'13': ['Doctors ']},
                  '8': {'31': ['Interview']}
                 }, 
           '2021': {}}

其中外键是年份,中间键是月份,最内键是日期,它导致事件列表。 我正在尝试首先对其进行排序,以便月份按顺序排列,然后再次对其进行排序,以便日期按顺序排列。提前致谢

【问题讨论】:

  • 那你要应用什么操作,迭代一遍?
  • 我正在考虑使用带键参数的排序,但我无法弄清楚如何访问内部字典我也不是 100% 排序的,所以如果你有更好的主意,那就太好了
  • 但是排序的目的是什么?字典不关心顺序:您使用它们来查找给定的键,它就可以完成工作。如果顺序很重要,那么为什么不使用嵌套列表呢?

标签: python sorting dictionary nested


【解决方案1】:

用例

  • DevOrangeCrush 希望对嵌套字典中的键进行排序,其中嵌套发生在多个级别上

解决方案

  • 规范化数据,使日期匹配ISO8601格式,以便于排序

    • 在简单的英语中,这意味着确保您始终使用两位数字表示月份和日期,始终使用四位数字表示年份
  • 将原始字典数据结构重新规范化为单个字典列表,其中每个字典代表一行,列表代表一个外部包含表

  • 一旦您的数据被重组,您将解决一个更知名、有据可查且更明显的问题,即如何对一个简单的字典列表进行排序(已在此答案的 See also 部分中记录) .

示例

import pprint

## original data is formatted as a nested dictionary, which is clumsy

my_dict = {'2020': 
   {'9': {'8': ['School ']}, '11': 
   {'13': ['Doctors ']},'8': 
   {'31': ['Interview']}}, '2021': {}
}

## we want the data formatted as a standard table (aka list of dictionary)
## this is the most common format for this kind of data as you would see in
## databases and spreadsheets

mydata_table  = []
ddtemp        = dict()
for year in my_dict:
  for month in my_dict[year].keys():
    ddtemp['month'] =   '{0:02d}'.format(*[int(month)])
    ddtemp['year']  =   year
    for day in my_dict[year][month].keys():
      ddtemp['day'] = '{0:02d}'.format(*[int(day)])
      mydata_row = dict()
      mydata_row['year']        =   '{year}'.format(**ddtemp)
      mydata_row['month']       =   '{month}'.format(**ddtemp)
      mydata_row['day']         =   '{day}'.format(**ddtemp)
      mydata_row['task_list']   =   my_dict[year][month][day]
      mydata_row['date']        =   '{year}-{month}-{day}'.format(**ddtemp)
      mydata_table.append(mydata_row)
    pass
  pass
pass

## output result is now easily sorted and there is no data loss
## you will have to modify this if you want to deal with years that
## do not have any associated task_list data

pprint.pprint(mydata_table)

'''

## now we have something that can be sorted using well-known python idioms
## and easily manipulated using data-table semantics 
## (search, sort, filter-by, group-by, select, project ... etc)

[
  {'date': '2020-09-08','day': '08',
    'month': '09','task_list': ['School '],'year': '2020'},
  {'date': '2020-11-13','day': '13',
    'month': '11','task_list': ['Doctors '],'year': '2020'},
  {'date': '2020-08-31','day': '31',
    'month': '08','task_list': ['Interview'],'year': '2020'},
]

'''

另见

【讨论】:

  • @OrangeCrush pprint 以易于阅读的格式转储一个大变量,您可以在任何时候使用它,只要您有大字典或 python 中的任意变量,并且您想查看其中的内容@ 987654328@pretty-print
【解决方案2】:

要获取排序后的事件数据,您可以执行以下操作:

def sort_events(my_dict):
    new_events_data = dict()
    for year, month_data in my_dict.items():
        new_month_data = dict()
        for month, day_data in month_data.items():
            sorted_day_data = sorted(day_data.items(), key=lambda kv: int(kv[0]))
            new_month_data[month] = OrderedDict(sorted_day_data)
        sorted_months_data = sorted(new_month_data.items(), key=lambda kv: int(kv[0]))
        new_events_data[year] = OrderedDict(sorted_months_data)
    return new_events_data

输出:

{'2020': OrderedDict([('8', OrderedDict([('31', ['Interview'])])),
              ('9', OrderedDict([('8', ['School '])])),
              ('11', OrderedDict([('13', ['Doctors '])]))]),
 '2021': OrderedDict()}

【讨论】:

    【解决方案3】:

    无法订购简单的 dict,您可以使用 OrderedDict 进行排序,但如果您只是需要在迭代时对其进行排序,请这样做

    for year in sorted(map(int, my_dict)):
        year_dict = my_dict[str(year)]
    
        for month in sorted(map(int, year_dict)):
            month_dict = year_dict[str(month)]
    
            for day in sorted(map(int, month_dict)):
                events = month_dict[str(day)]
    
                for event in events:
                    print(year, month, day, event)
    

    Online Demo

    转换为int 是为了确保数字之间的正确排序,否则您将得到1, 10, 11, .., 2, 20, 21

    【讨论】:

      【解决方案4】:

      Python 中的字典没有顺序,您可能想尝试集合模块中的 OrderedDict 类,该类会记住插入顺序。

      当然,每当您插入一个应该放在任何现有元素之前的新元素时,您都必须对元素进行排序并重新插入。

      如果您关心顺序,则不同的数据结构可能会更好。例如列表列表。

      【讨论】:

      • 这应该是评论,而不是答案。
      • 很遗憾,由于声誉低,我无法在这里发表评论
      • ...这不是错误发布的许可。
      • 好的,那么如何获得编写 cmets 所需的初始声誉?
      • 该信息以及更多信息包含在您注册时获取的intro tour 中。我通过审查事情来完成我的工作。
      猜你喜欢
      • 2019-11-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-05-14
      • 2011-11-29
      • 1970-01-01
      相关资源
      最近更新 更多