Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Adding to values in a dictionary from two lists of different length

Tags:

python

list

I have four lists that look like this:

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]

lista and listanum are synchronized, listb and listbnum too. I want to make a dictionary where the keys are the items in listanum and the values are items in lista and listb, the outcome would be:

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

so if there is no value for a number in listanum in listb, the second list in the dictionarys values is empty.

I have tried this:

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])

but get this error message: 'IndexError: list index out of range'. I cant see why it is out of range???

like image 741
edg Avatar asked Apr 12 '13 14:04

edg


People also ask

Can you use LEN () on a dictionary?

To calculate the length of a dictionary, we can use the Python built-in len() method. The len() method returns the number of keys in a Python dictionary.

How do you add two values in a dictionary?

To merge two dictionaries and sum the values: Use a dict comprehension to iterate over one of the dictionaries. On each iteration, use the dict. get() method to sum the values.

How do I sum a list of values in a dictionary?

To sum the values in a list of dictionaries: Use a generator expression to iterate over the list. On each iteration, access the current dictionary at the specific key. Pass the generator expression to the sum() function.


2 Answers

Zip the items, and use collections.defaultdict to default the values to lists:

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)

I used chain to make looping over both sets of key-value pairs easier; this works in both Python 2 and 3. If this is Python 2 only code, you could use + to concatenate the two lists.

Output with pprint and converting back to a regular dict to make printing easier:

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

This does not create empty lists for the second set; if you have to have empty lists, you are limited to building two separate dictionaries then merging those:

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()}

for Python 2, for Python 3 use .keys() instead of .viewkeys(), to produce:

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

Specifically, for your code, you confused i (the index into lista) with pos:

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

For i = 4, i in listbnum is True, but listb[4] does not exist. Your code also tried to append the lists from lista and listb, which would not result in the correct output.

Altering your version a little to work, using a separate loop for the listb/listbnum lists:

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]
like image 127
Martijn Pieters Avatar answered Oct 31 '22 11:10

Martijn Pieters


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'], []]}
like image 5
NPE Avatar answered Oct 31 '22 10:10

NPE