使用列表推导创建一个字典并将值推送到列表

时间:2017-03-18 22:03:31

标签: python list dictionary list-comprehension

我希望你能解决我目前遇到的问题。我需要构建一个具有以下结构的字典:

iplist={'32': [ '100.107.0.31/32', '100.107.0.3/32' ]
       ,'24': [ '100.107.0.0/24', '100.107.1.0/24', '100.107.2.0/24' ]
       ,'22': [ '100.107.0.0/22' ]
       ,'20': [ '100.107.0.0/20', '100.107.64.0/20' ]
       ,'16': [ '100.68.0.0/16', '100.69.0.0/16' ]
       ,'0' : [ '0.0.0.0' ] }

输入数据将是这个,我只需要键:

netlabels={'100.107.0.31/32': 'aa'
          ,'100.107.0.3/32' : 'bb'
          ,'100.107.0.0/24' : 'cc'
          ,'100.107.1.0/24' : 'dd'
          ,'100.107.2.0/24' : 'ee'
          ,'100.107.0.0/22' : 'ff'
          ,'100.107.0.0/20' : 'gg'
          ,'100.107.64.0/20': 'hh'
          ,'100.68.0.0/16'  : 'hh'
          ,'100.69.0.0/16'  : 'hh'
          ,'0.0.0.0/0'      : 'ii'}

我尝试使用正则表达式和列表理解来完成它,因为将它全部放在一个代码行中真的很酷。我的上一次成功'尝试是这样的:

>>> import re
>>> netlabels={'100.107.0.31/32' : 'aa'
... ,'100.107.0.3/32' : 'bb'
... ,'100.107.0.0/24' : 'cc'
... ,'100.107.1.0/24' : 'dd'
... ,'100.107.2.0/24' : 'ee'
... ,'100.107.0.0/22' : 'ff'
... ,'100.107.0.0/20' : 'gg'
... ,'100.107.64.0/20': 'hh'
... ,'100.68.0.0/16'  : 'hh'
... ,'100.69.0.0/16'  : 'hh'
... ,'0.0.0.0/0'      : 'ii'}
>>> 
>>> { re.sub(r'^[^/]+/(\d+)$', r'\1', k) : [k] for k in netlabels.keys() }
{'16': ['100.69.0.0/16'], '24': ['100.107.1.0/24'], '22': ['100.107.0.0/22'], '0': ['0.0.0.0/0'], '20': ['100.107.0.0/20'], '32': ['100.107.0.3/32']}
>>> 

但显然列表的值太短了。有许多前缀刚被删除,或者更确切地说,被覆盖。每次需要添加新值时,如何在列表中推送值并附加此列表?

2 个答案:

答案 0 :(得分:1)

它真的值得重复:"拥有这一条线就很酷#34;是一个可怕的设计理由。做你想做的事情的方法是使用defaultdict。另外,我认为你可以不使用正则表达式。

In [5]: data = {  '100.107.0.31/32' : 'aa',
   ...:   '100.107.0.3/32'  : 'bb',
   ...:   '100.107.0.0/24'  : 'cc',
   ...:   '100.107.1.0/24'  : 'dd',
   ...:   '100.107.2.0/24'  : 'ee',
   ...:   '100.107.0.0/22'  : 'ff',
   ...:   '100.107.0.0/20'  : 'gg',
   ...:   '100.107.64.0/20' : 'hh',
   ...:   '100.68.0.0/16'   : 'hh',
   ...:   '100.69.0.0/16'   : 'hh',
   ...:   '0.0.0.0/0'       : 'ii'}

In [6]: from collections import defaultdict

In [7]: transformed = defaultdict(list)

In [8]: for key in data:
   ...:     _,_,k = key.rpartition('/')
   ...:     transformed[k].append(key)
   ...:

结果:

In [10]: transformed
Out[10]:
defaultdict(list,
            {'0': ['0.0.0.0/0'],
             '16': ['100.68.0.0/16', '100.69.0.0/16'],
             '20': ['100.107.0.0/20', '100.107.64.0/20'],
             '22': ['100.107.0.0/22'],
             '24': ['100.107.0.0/24', '100.107.1.0/24', '100.107.2.0/24'],
             '32': ['100.107.0.31/32', '100.107.0.3/32']})

你可以在一条线上实现上述目标,但它可能完全不可读,并且可能不会有任何效率。

defaultdict的替代方法是使用香草setdefault的{​​{1}}方法:

dict

答案 1 :(得分:0)

Juanpa的答案有效,但如果你仍然想使用re和一行代码,你可以这样做:

>>> import re
>>> netlabels={'100.107.0.31/32' : 'aa'
,'100.107.0.3/32' : 'bb'
,'100.107.0.0/24' : 'cc'
,'100.107.1.0/24' : 'dd'
,'100.107.2.0/24' : 'ee'
,'100.107.0.0/22' : 'ff'
,'100.107.0.0/20' : 'gg'
,'100.107.64.0/20': 'hh'
,'100.68.0.0/16'  : 'hh'
,'100.69.0.0/16'  : 'hh'}
>>> dct ={}
>>> {dct .setdefault(re.sub(r'^[^/]+/(\d+)$', r'\1', k), []).append(k) for k in netlabels.keys()}
set([None])
>>> dct
{'24': ['100.107.0.0/24', '100.107.1.0/24', '100.107.2.0/24'], '32': ['100.107.0.31/32', '100.107.0.3/32'], '20': ['100.107.0.0/20', '100.107.64.0/20'], '22': ['100.107.0.0/22'], '16': ['100.69.0.0/16', '100.68.0.0/16']}
>>>