【问题标题】:Sort multiple dictionaries identically, based on a specific order defined by a list根据列表定义的特定顺序对多个字典进行相同的排序
【发布时间】:2017-01-22 05:58:39
【问题描述】:

我有一个特殊情况,必须根据列表中项目的确切顺序(不是字母顺序)对多个现有字典进行排序。例如,字典是:

dict_one = {"LastName": "Bar", "FirstName": "Foo", "Address": "Example Street 101", "Phone": "012345678"}
dict_two = {"Phone": "001122334455", "LastName": "Spammer", "FirstName": "Egg", "Address": "SSStreet 123"}
dict_three = {"Address": "Run Down Street 66", "Phone": "0987654321", "LastName": "Biker", "FirstName": "Random"}

名单是:

data_order = ["FirstName", "LastName", "Phone", "Address"]

预期结果是能够创建这样的文件:

FirstName;LastName;Phone;Address
Foo;Bar;012345678;Example Street 101
Egg;Spammer;001122334455;SSStreet 123
Random;Biker;0987654321;Run Down Street 66

注意: 就我而言,真正的用途是使用 pyexcel-xls 的 Excel 文件,但上面的类似 CSV 的示例可能更接近于通常所做的,因此答案可能比 Excel 更普遍适用于 CSV。

【问题讨论】:

    标签: python python-3.x sorting


    【解决方案1】:

    对于这种情况,我很难在 Stack Overflow 中找到任何好的答案,但最终我得到了排序工作,我可以用它来创建文件。标题行可以直接从下面的data_order 列表中获取。以下是我的做法 - 希望对某人有所帮助:

    from collections import OrderedDict
    import pprint
    
    dict_one = {
        "LastName": "Bar", 
        "FirstName": "Foo", 
        "Address": "Example Street 101", 
        "Phone": "012345678"}
    dict_two = {
        "Phone": "001122334455", 
        "LastName": "Spammer", 
        "FirstName": "Egg", 
        "Address": "SSStreet 123"}  
    dict_three = {
        "Address": "Run Down Street 66", 
        "Phone": "0987654321", 
        "LastName": "Biker", 
        "FirstName": "Random"}
    
    dict_list = []
    dict_list.append(dict_one)
    dict_list.append(dict_two)
    dict_list.append(dict_three)
    
    data_order = ["FirstName", "LastName", "Phone", "Address"]
    
    result = []
    for dictionary in dict_list:
        result_dict = OrderedDict()
        # Go through the data_order in order
        for key in data_order:
            # Populate result_dict in the list order
            result_dict[key] = dictionary[key]
        result.append(result_dict)
    
    pp = pprint.PrettyPrinter(indent=4)
    pp.pprint(result)
    """
    [   {   'FirstName': 'Foo',
            'LastName': 'Bar',
            'Phone': '012345678',
            'Address': 'Example Street 101'},
        {   'FirstName': 'Egg',
            'LastName': 'Spammer',
            'Phone': '001122334455',
            'Address': 'SSStreet 123'},
        {   'FirstName': 'Random',
            'LastName': 'Biker',
            'Phone': '0987654321',
            'Address': 'Run Down Street 66'}]
    """
    

    【讨论】:

      【解决方案2】:

      这可以在单行中实现,尽管它更难阅读。如果它对某人有用:

      print [OrderedDict([(key, d[key]) for key in data_order]) for d in [dict_one, dict_two, dict_three]]
      

      【讨论】:

      • 仅供参考,OrderedDict 参数中的内括号不是必需的(当OrderedDict 可以接受生成器表达式并避免使用临时表达式时,它们只是临时生成list)。这将在没有临时使用基因expr 的情况下工作:OrderedDict((key, d[key]) for key in data_order)。或者对于加分,使用operator.itemgetter:fields = itemgetter(*data_order),然后print [OrderedDict(zip(data_order, fields(d))) for d in (dict_one, dict_two, dict_three)] 完全删除listcomp/genexpr,将更多工作推到C 层并减少冗长。 :-)
      【解决方案3】:

      这是 csv.DictWriter 的经典用例,因为您的预期输出类似于 CSV(支持分号分隔符而不是逗号),它将为您处理所有这些,避免需要涉及 @ 的荒谬解决方法987654324@,并且可以轻松地读回数据而不必担心极端情况(csv 会在必要时自动引用字段,并根据需要在读入时解析引用的字段):

      with open('outputfile.txt', 'w', newline='') as f:
          csvout = csv.DictWriter(f, data_order, delimiter=';')
      
          # Write the header
          csvout.writeheader()
          csvout.writerow(dict_one)
          csvout.writerow(dict_two)
          csvout.writerow(dict_three)
      

      就是这样,csv 处理排序,(它知道从作为fieldnames 传递到DictWriter 构造函数的data_order 的正确顺序)、格式化等。


      如果您需要以特定顺序从许多 dicts 中提取值而不编写它们(因为您的用例甚至不使用键),operator.itemgetter 可用于显着简化此操作:

      from operator import itemgetter
      
      getfields = itemgetter(*data_order)
      
      dict_one_fields = getfields(dict_one)
      

      它将dict_one_fields 保留为tuple,请求的字段按请求的顺序,('Foo', 'Bar', '012345678', 'Example Street 101'),并且运行速度明显快于在 Python 层重复索引(itemgetter 创建一个 C 级“函子”,可以在一次调用中检索所有请求的值,对于像 str 这样的内置键完全没有 Python 级别的字节码。

      【讨论】:

      • 好吧,实际上我必须制作一个 Excel 文件,但在我的示例中使用了 CSV,因为它更常见 :)
      • @JuhaUntinen:如果是真正的 CSV(您使用分号,Excel 使用逗号),您可以制作一个实际的 CSV 文件(没有自定义 delimitercsv 模块默认为 Excel 兼容CSV方言,并以.csv扩展名命名文件),您可能不需要制作真正的Excel文件。 Excel 本机理解 CSV。如果您只需要 Excel 加载它,而不是专门以 Excel 的本机格式加载,则可以节省一些工作量。否则,我的答案的后半部分对于获取值以便与.xlsx writer 包一起使用仍然有用;它更快/更简单,并且避免重新发明轮子。
      猜你喜欢
      • 2011-04-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-01-21
      • 1970-01-01
      • 2020-11-01
      • 1970-01-01
      • 2022-11-16
      相关资源
      最近更新 更多