Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Python- add to dictionary based on an incrementing value in 2 lists

I have 2 lists which i have created and added an incrementing value to each item. The reason being that the values in each list are to be joined together in a dictionary. However the values in each list are not a 1 to 1 pair..this is why i added the incrementing values to assist with associating each key with it's corresponding value(s).

Here is some example data from my lists:

list_a = ['abc|1','bcd|2','cde|3']
list_b = ['1234|1','2345|2','3456|2','4567|2','5678|3']

So ideally what i am looking to do is run through both lists and then produce a dictionary based on pairing by the incrementing values. I am guessing the values where applicable would have to be a list?

Below is the ideal output:

my_dict = {'abc|1':'1234|1','bcd|2':['2345|2','3456|2','4567|2'],'cde|3':'5678|3'}    

Any help would be greatly appreciated, Thanks in advance :)

like image 726
Nunchux Avatar asked May 20 '15 10:05

Nunchux


3 Answers

list_a = ['abc|1','bcd|2','cde|3']
list_b = ['1234|1','2345|2','3456|2','4567|2','5678|3']

tmp = {k.split('|')[1]: (k, []) for k in list_a}
for v in list_b:
    tmp[v.split('|')[1]][1].append(v)
my_dict = dict(tmp.values())

This gets close to what you posted as goal, but I think it's actually better.

goal: {'abc|1':  '1234|1',  'bcd|2': ['2345|2', '3456|2', '4567|2'], 'cde|3':  '5678|3' }
mine: {'abc|1': ['1234|1'], 'bcd|2': ['2345|2', '3456|2', '4567|2'], 'cde|3': ['5678|3']}

You can see we only differ by putting singles into a list (me) or not (you). The reason I think my way is better is because any code using this result will likely be easier if all values are lists, so it doesn't need to handle both single strings and lists of strings. Just like it was easier for me to produce only lists.

But if you still prefer your way, change my above last line to:

my_dict = {k: v if len(v) > 1 else v[0] for k, v in tmp.values()}
like image 132
Stefan Pochmann Avatar answered Nov 14 '22 00:11

Stefan Pochmann


You could make two dicts grouping with the first:

list_a = ['abc|1','bcd|2','cde|3']
list_b = ['1234|1','2345|2','3456|2','4567|2','5678|3']

d = defaultdict(list)
from itertools import chain
for k in chain(list_a,list_b):
    d[k.rsplit("|",1)[1]].append(k)
print(d)

print({v[0]:v[1:] for v in d.values()})

defaultdict(<type 'list'>, {'1': ['abc|1', '1234|1'], '3': ['cde|3', '5678|3'], '2': ['bcd|2', '2345|2', '3456|2', '4567|2']})
{'abc|1': ['1234|1'], 'cde|3': ['5678|3'], 'bcd|2': ['2345|2', '3456|2', '4567|2']}

You can avoid the list for single values by checking the length first if required.

d = {v[0]: (v[1:] if len(v)> 2 else v[-1]) for v in d.values()}
print(d)

{'abc|1': '1234|1', 'cde|3': '5678|3', 'bcd|2': ['2345|2', '3456|2', '4567|2']}

Using python3 the syntax is a bit nicer using extended iterable unpacking:

d = {k: (val if len(val) > 1 else val[0]) for k,*val in d.values()}
print(d)

If you want order based on the keys in the lista you will need an OrderedDict:

list_a = ['abc|1', 'bcd|2', 'cde|3']
list_b = ['1234|1', '2345|2', '3456|2', '4567|2', '5678|3']
from collections import OrderedDict
from itertools import chain

od = OrderedDict()

for k in chain(list_a, list_b):
    od.setdefault(k.rsplit("|",1)[1], []).append(k)

d = OrderedDict((k, (val)) for k, *val in od.values())
like image 26
Padraic Cunningham Avatar answered Nov 13 '22 22:11

Padraic Cunningham


It can be achieved from something like this

temp_dict = {}
for x in list_a:
    val = x.split('|')[1]
    temp_dict[x] = [y for y in list_b if y.endswith("|" + val)]
like image 2
shaktimaan Avatar answered Nov 13 '22 22:11

shaktimaan