【问题标题】:Pythonic way to convert list of dicts into list of namedtuples将字典列表转换为命名元组列表的 Pythonic 方法
【发布时间】:2011-12-11 13:27:10
【问题描述】:

我有一个 listdict。需要将其转换为listnamedtuple(首选)或简单的tuple 同时用空格分割第一个变量。

还有什么更 Pythonic 的方法?

我稍微简化了我的代码。欢迎理解、gen 表达式和 itertools 使用。

数据输入:

dl = [{'a': '1 2 3',
       'd': '*',
       'n': 'first'},
      {'a': '4 5',
       'd': '*', 'n':
       'second'},
      {'a': '6',
       'd': '*',
       'n': 'third'},
      {'a': '7 8 9 10',
       'd': '*',
       'n': 'forth'}]

简单算法:

from collections import namedtuple

some = namedtuple('some', ['a', 'd', 'n'])

items = []
for m in dl:
    a, d, n = m.values()
    a = a.split()
    items.append(some(a, d, n))

输出:

[some(a=['1', '2', '3'], d='*', n='first'),
 some(a=['4', '5'], d='*', n='second'),
 some(a=['6'], d='*', n='third'),
 some(a=['7', '8', '9', '10'], d='*', n='forth')]

【问题讨论】:

    标签: algorithm list dictionary python


    【解决方案1】:

    我想在这里插话只是因为我非常喜欢命名元组和字典!

    这是一个包含字典理解的列表理解,可以对字典进行初始处理:

    split_dictionaries = \ 
        [{key: value.split() for k, value in d.iteritems()} for d in dl] 
    

    我经常使用一种我称之为“tupperware”的配方,它可以递归地将字典转换为命名元组。有关代码,请参阅the gist here。这是它的一个简化部分,可以在这里集成,并且有一种非常简洁的方式来执行此操作。

    import collections
    
    def namedtuple_from_mapping(mapping, name="Tupperware"):
        this_namedtuple_maker = collections.namedtuple(name, mapping.iterkeys())
        return this_namedtuple_maker(**mapping)
    

    因此,鉴于该功能,您可以执行此操作 - 我们将很快对其进行重构:

    split_namedtuples = [ 
        namedtuple_from_mapping(
            {key: value.split() for k, value in d.iteritems()}
        ) for d in dl
    ]   
    

    现在有了更好的封装性和可读性:

    def format_string(string):
        return string.split()
    
    def format_dict(d):
        return {key: format_string(value) for key, value in d.iteritems()}
    
    formatted_namedtuples = [namedtuple_from_mapping(format_dict(d)) for d in dl]
    

    【讨论】:

      【解决方案2】:

      下面,@Petr Viktorin 指出了我的原始答案和您的初始解决方案的问题:

      警告!字典的 values() 没有任何特定的顺序!如果这个解决方案有效,并且 a、d、n 真的按该顺序返回,那只是巧合。如果您使用不同版本的 Python 或以不同方式创建 dicts,它可能会损坏。

      (我有点惭愧,我一开始没有选择这个,并为此获得了 45 个代表!)

      改用@eryksun 的建议:

      items =  [some(m['a'].split(), m['d'], m['n']) for m in dl]
      

      我原来的错误答案。除非您有OrderedDict 的列表,否则不要使用它。

      items =  [some(a.split(), d, n) for a,d,n in (m.values() for m in dl)]
      

      【讨论】:

      • 警告!字典are not in any particular ordervalues()!如果此解决方案有效,并且 a, d, n 确实按该顺序返回,那只是巧合。如果您使用不同版本的 Python 或以不同的方式创建字典,它可能会损坏。直接使用密钥,如@eryksun 的评论中所示。
      • @PetrViktorin - 哇,我不敢相信我错过了。谢谢指正!
      • @PetrViktorin 我怎么能忘记...将改用OrderedDict
      • 我发现namedtuple('xxx', d.keys())(**d) 非常方便。
      【解决方案3】:

      另一个选项,不确定它比其他选项更好还是更差:

      class some(namedtuple('some', 'a d n')):
          def __new__(cls, **args):
              args['a'] = args['a'].split()
              return super(some, cls).__new__(cls, **args)
      
      items = list(some(**m) for m in dl)
      

      顺便说一句,我并不绝对承诺将基类与子类some 同名。我喜欢它,因为这意味着生成的类使用名称some 转换为字符串,并且它从来没有给我带来特别的问题,但是如果您使用类名进行调试,它可能会令人困惑。所以要小心。

      或者相同的想法使用不同的技巧:

      some = namedtuple('some', 'a d n')
      
      def make_some(args):
          args = args.copy()
          args['a'] = args['a'].split()
          return some(**args)
      
      items = map(make_some, dl) # NB: this doesn't return a list in Python 3
      

      【讨论】:

        【解决方案4】:

        除了@detly提供的答案,如果你事先不知道dicts的字段,你可以用

        构造一个namedtuple
        some = namedtuple('some', set(k for k in d.keys() for d in dl))
        

        【讨论】:

          猜你喜欢
          • 2019-11-19
          • 1970-01-01
          • 1970-01-01
          • 2013-04-01
          • 1970-01-01
          • 2021-11-10
          • 1970-01-01
          • 1970-01-01
          • 2010-09-20
          相关资源
          最近更新 更多