从两个不同长度的列表中添加到字典值中

5

我有四个类似这样的列表:

lista = [['l', 'k'],['e', '3'],['c', 'k'],['x', 'i'],['d', 'f']]
listanum = [1,2,3,4,5]
listb = [['a', 'k'],['c', 'm'],['v', 'f']]
listbnum = [1,3,4]

listalistanum是同步的,listblistbnum也是如此。 我想创建一个字典,其中键是listanum中的项目,而值是listalistb中的项目,结果将会是:

di = {1: [['l','k'],['a', 'k']], 
      2: [['e', '3'],[]], 
      3:[['c','k'],['c', 'm']], 
      4: [['x', 'i'],['v', 'f']], 
      5: [['d', 'f'][]]
}

所以如果在listb中没有listanum中数字的值,那么字典中第二个列表的值为空。

我尝试过这样做:

di = {}
for i in xrange(len(lista)):
  pos = listanum[i]
  if pos not in di:
    di[pos] = [[],[]]
  di[pos][0].append(lista[i])  
  if i in listbnum:
    di[pos][1].append(listb[i])

但是我收到了这个错误信息:'IndexError: list index out of range'。我看不出为什么它超出了范围???

2个回答

5
In [7]: da = dict(zip(listanum, lista))

In [8]: db = dict(zip(listbnum, listb))

In [9]: {k:[da.get(k,[]), db.get(k,[])] for k in set(listanum + listbnum)}
Out[9]: 
{1: [['l', 'k'], ['a', 'k']],
 2: [['e', '3'], []],
 3: [['c', 'k'], ['c', 'm']],
 4: [['x', 'i'], ['v', 'f']],
 5: [['d', 'f'], []]}

+1,但我会用 da.keys() | db.keys()(或在2.7中使用da.viewkeys() | db.viewkeys())替换set(listanum + listbnum) - Gareth Latty
@Lattyware:谢谢你的建议。我对我回答中的版本的论点是它在2.7和3.x之间都是可移植的。 - NPE
虽然2to3应该可以轻松地将dict.viewkeys()转换为dict.keys(),但这并不是什么大问题,两者都很易读。 - Gareth Latty
我的代码有什么问题?为什么它超出范围?如何在不使用zip函数并且不在一行中编写代码(使逻辑更清晰)? - edg

5

将这些项目压缩,并使用collections.defaultdict将值默认为list

from itertools import chain
from collections import defaultdict

di = defaultdict(list)

for key, value in chain(zip(listanum, lista), zip(listbnum, listb)):
    di[key].append(value)

我使用了chain,以便更轻松地循环遍历两组键值对;这在Python 2和3中均适用。如果这是仅适用于Python 2的代码,您可以使用+连接两个列表。

使用pprint输出并转换回常规dict以使打印更容易:
>>> pprint(dict(di))
{1: [['l', 'k'], ['a', 'k']],
 2: [['e', '3']],
 3: [['c', 'k'], ['c', 'm']],
 4: [['x', 'i'], ['v', 'f']],
 5: [['d', 'f']]}

这不会为第二组创建空列表;如果您必须有空列表,则只能构建两个单独的字典,然后合并它们:

dicta = dict(zip(listanum, lista))
dictb = dict(zip(listbnum, listb))

di = {k: [dicta.get(k, []), dictb.get(k, [])] for k in dicta.viewkeys() | dictb.viewkeys()}

如果是Python 2,使用.viewkeys(),如果是Python 3,则使用.keys(),以生成:

>>> pprint(di)
{1: [['l', 'k'], ['a', 'k']],
 2: [['e', '3'], []],
 3: [['c', 'k'], ['c', 'm']],
 4: [['x', 'i'], ['v', 'f']],
 5: [['d', 'f'], []]}

具体来说,对于你的代码,你把 i(列表 lista 中的索引)和 pos 弄混了:

  if i in listbnum:
    di[pos][1].append(listb[i])

对于 i = 4i in listbnumTrue,但是 listb[4] 不存在。你的代码还试图将来自 listalistb 的列表进行 追加,这不会得到正确的输出。
稍微修改你的版本以使其工作,使用一个 单独的 循环来处理 listb/listbnum 列表:
di = {}
for i, pos in enumerate(listanum):
    if pos not in di:
        di[pos] = [[],[]]
    di[pos][0][:] = lista[i]

for i, pos in enumerate(listbnum):
    di[pos][1][:] = listb[i]

在这种情况下,一个 “+” 不足以取代链吗? - Joran Beasley
@JoranBeasley:如果这是 Python 3,就不是这样。 - Martijn Pieters
我的代码有什么问题?为什么它超出了范围?难道问题不是可以通过修改我的代码而不是使用chain和defaultdict函数轻松解决吗? - edg

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接