【问题标题】:change a list into dictionary将列表更改为字典
【发布时间】:2016-05-29 18:34:55
【问题描述】:

如何更改这样的列表:

[[0, 'Ealing Broadway', 103.89],
 [0, 'Notting Hill Gate', 103.89],
 [0, 'Mile End', 103.89],
 [1, 'Ealing Broadway', 59.089999999999996],
 [2, 'Notting Hill Gate', 40.279999999999994],
 [3, 'Mile End', 68.86999999999999]]

像字典一样

{0:{'length':103.89,'interchange':['Ealing Broadway','Notting Hill Gate','Mile End']},
1:{'length':59.089999999999996,'interchange':['Ealing Broadway']},
2:{'length':40.279999999999994,'interchange':['Notting Hill Gate']},
3:{'length':68.86999999999999,'interchange':['Mile End']}}

谢谢

I am trying to start with:

d2 = defaultdict(list)
for k, v in all_info:
    d2[k].append(v)

with_length=dict((k,list(v)) for k,v in d2.iteritems())
with_length

但它不起作用,我正在努力从哪里开始。

【问题讨论】:

  • 子列表中第一个元素的值是否总是表示子列表中最后一个元素的值相同?
  • 我很好奇这些“长度”指的是什么。平台长度?
  • 0,1,2,3 可以理解为路由。车站名称是这条路线的交汇处。最终值是路线的长度。
  • 你可以用pandas模块解决吗?
  • 我不这么认为,因为我需要处理大量数据。 Pandas 可能会减慢这个过程。

标签: python list dictionary key-value-store


【解决方案1】:

与 Majora 类似的答案,但首先使用 groupby。没有错误的查找,但可能需要事先进行排序。

from itertools import groupby

lst = [[0, 'Ealing Broadway', 103.89],
    [0, 'Notting Hill Gate', 103.89],
    [0, 'Mile End', 103.89],
    [1, 'Ealing Broadway', 59.089999999999996],
    [2, 'Notting Hill Gate', 40.279999999999994],
    [3, 'Mile End', 68.86999999999999]]

new_list = []
for key, group in groupby(lst, lambda x: x[0]):
    new_list.append(list(group))

main_dict = {}
for item in new_list:
    main_dict[item[0][0]] = {'length': item[0][2], 'interchange': [stn[1] for stn in item]}

【讨论】:

    【解决方案2】:

    这里有一个具体的例子来说明你将如何做到这一点:

    l = [[0, 'Ealing Broadway', 103.89],
         [0, 'Notting Hill Gate', 103.89],
         [0, 'Mile End', 103.89],
         [1, 'Ealing Broadway', 59.089999999999996],
         [2, 'Notting Hill Gate', 40.279999999999994],
         [3, 'Mile End', 68.86999999999999]]
    
    d = {}
    
    for pair in l:
        if pair[0] not in d.keys():
            d[pair[0]] = { 'interchange': [] }
    
        d[pair[0]]['length'] = pair[2]
        d[pair[0]]['interchange'].append(pair[1])
    

    这是假设您在向d[0] 添加元素时要覆盖d['length']

    【讨论】:

      【解决方案3】:
      b = {}
      for i in a:
          if b.has_key(i[0]):
              b[i[0]]['interchange'].append(i[1])
          else:
              b[i[0]] = {'length': i[2], 'interchange': [i[1]]}
      

      【讨论】:

      • 这与我的答案的第二次编辑几乎完全相同。
      • @Majora320 这也不是一个完整的测试答案。我不确定这是如何排名最高的。我选择回答不是因为我认为我有最好的,而是如果我自己的答案不适合问题,我会批评它。
      【解决方案4】:

      这是一种需要两次通过的方法。它的优点是易于理解。

      import pprint
      
      if __name__ == '__main__':
          rows = [
              [0, 'Ealing Broadway', 103.89],
              [0, 'Notting Hill Gate', 103.89],
              [0, 'Mile End', 103.89],
              [1, 'Ealing Broadway', 59.089999999999996],
              [2, 'Notting Hill Gate', 40.279999999999994],
              [3, 'Mile End', 68.86999999999999]]
      
          print('First Pass')
          d = {}
          for key, interchange, length in rows:
              inner_dict = d.setdefault((key, length), {})
              interchanges = inner_dict.setdefault('interchange', [])
              interchanges.append(interchange)
      
          pprint.pprint(d)
      
          print('=' * 72)
          print('Second Pass')
          d2 = {}
          for (key, length), v in d.items():
              v['length'] = length
              d2[key] = v
      
          pprint.pprint(d2)
      

      输出

      First Pass
      {(0, 103.89): {'interchange': ['Ealing Broadway',
                                     'Notting Hill Gate',
                                     'Mile End']},
       (1, 59.089999999999996): {'interchange': ['Ealing Broadway']},
       (2, 40.279999999999994): {'interchange': ['Notting Hill Gate']},
       (3, 68.86999999999999): {'interchange': ['Mile End']}}
      ========================================================================
      Second Pass
      {0: {'interchange': ['Ealing Broadway', 'Notting Hill Gate', 'Mile End'],
           'length': 103.89},
       1: {'interchange': ['Ealing Broadway'], 'length': 59.089999999999996},
       2: {'interchange': ['Notting Hill Gate'], 'length': 40.279999999999994},
       3: {'interchange': ['Mile End'], 'length': 68.86999999999999}}
      

      讨论

      • 在第一遍中,我使用第一列和最后一列作为字典的键。这个字典的值是另一个字典 (inner_dict)
      • 在第二遍中,我将键和值调整为最终形式。
      • 此解决方案可能不是最有效或最优雅的,但我希望它易于理解

      【讨论】:

        【解决方案5】:

        请将我的回答视为 Pandas(强大的 Python 数据分析工具包)模块方法的演示。

        我很确定您是否想要快速处理大量数据 - pandas 是您的工具...

        import pandas as pd
        
        data = [[0, 'Ealing Broadway', 103.89],
                [0, 'Notting Hill Gate', 103.89],
                [0, 'Mile End', 103.89],
                [1, 'Ealing Broadway', 59.089999999999996],
                [2, 'Notting Hill Gate', 40.279999999999994],
                [3, 'Mile End', 68.86999999999999]
               ]
        
        # create pandas DF
        df = pd.DataFrame(data, columns=['route','interchange','length'])
        

        原始 DF:

        In [235]: df
        Out[235]:
           route        interchange  length
        0      0    Ealing Broadway  103.89
        1      0  Notting Hill Gate  103.89
        2      0           Mile End  103.89
        3      1    Ealing Broadway   59.09
        4      2  Notting Hill Gate   40.28
        5      3           Mile End   68.87
        

        让我们对数据进行分组:

        In [239]: df.groupby(['route','length'])['interchange'].apply(lambda x: x.tolist()).reset_index()
        Out[239]:
           route  length                                     interchange
        0      0  103.89  [Ealing Broadway, Notting Hill Gate, Mile End]
        1      1   59.09                               [Ealing Broadway]
        2      2   40.28                             [Notting Hill Gate]
        3      3   68.87                                      [Mile End]
        

        我们也可以将其转换为字典列表:

        In [240]: df.groupby(['route','length'])['interchange'].apply(lambda x: x.tolist()).reset_index().to_dict('record')
        Out[240]:
        [{'interchange': ['Ealing Broadway', 'Notting Hill Gate', 'Mile End'],
          'length': 103.89,
          'route': 0},
         {'interchange': ['Ealing Broadway'],
          'length': 59.089999999999996,
          'route': 1},
         {'interchange': ['Notting Hill Gate'],
          'length': 40.279999999999994,
          'route': 2},
         {'interchange': ['Mile End'], 'length': 68.86999999999999, 'route': 3}]
        

        在我的家庭笔记本上为 600.000 行数据框计时:

        设置:

        In [245]: a = pd.concat([df] * 10**5)
        

        合并aDF的形状:

        In [246]: a.shape
        Out[246]: (600000, 3)
        

        时间:

        In [251]: %timeit a.groupby(['route','length'])['interchange'].apply(lambda x: x.tolist()).reset_index()
        10 loops, best of 3: 130 ms per loop
        

        非向量化方法(用于循环/列表理解/等):

        In [262]: %paste
        def roganjosh(lst):
            new_list = []
            for key, group in groupby(lst, lambda x: x[0]):
                new_list.append(list(group))
        
            main_dict = {}
            for item in new_list:
                main_dict[item[0][0]] = {'length': item[0][2], 'interchange': [stn[1] for stn in item]}
        
            return  main_dict
        ## -- End pasted text --
        
        In [263]: lst = a.values.tolist()
        
        In [264]: len(lst)
        Out[264]: 600000
        
        In [265]: %timeit roganjosh(lst)
        1 loop, best of 3: 650 ms per loop
        

        【讨论】:

        • 你输了length
        • @roganjosh,你是对的,谢谢!我已经更正了我的答案
        • :) 我想我该打timeit heh了
        • @roganjosh,是的,请,但请为 100K - 100M 行执行此操作;)
        • @roganjosh,我使用 pandas 为 600K 行 DF 添加了“timeit”结果;)
        猜你喜欢
        • 2020-12-07
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-01-20
        • 2019-02-01
        • 1970-01-01
        相关资源
        最近更新 更多