Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Combining two dicts into a list

Tags:

python

I have two dictionaries,i want to combine these two int a list in the format keys-->values,keys-->values... remove any None or ['']

currently I have the below where I can combine the dicts but not create a combined lists...i have the expecte output.. any inputs appreeciated

dict1={'313115': ['313113'], '311957': None}
dict2={'253036': [''], '305403': [], '12345': ['']}

dict = dict(dict1.items() + dict2.items())
print dict

{'313115': ['313113'], '311957': None, '253036': [''], '12345': [''], '305403': []}

EXPECTED OUTPUT:
['313115','313113','311957','253036','305403','12345']
like image 758
carte blanche Avatar asked Mar 24 '26 08:03

carte blanche


2 Answers

This should do it:

[i for k, v in (dict1.items() + dict2.items()) for i in [k] + (v or []) if i]

walk the combined items of the two dicts, then walk the key plus the list of values, returning each item from the second walk that exists.

Returns ['313115', '313113', '311957', '253036', '12345', '305403'] on your example dicts -- the order is different because python's dict iteration is unordered.

EDIT:

dict.items() can be expensive on large dicts -- it takes O(n) size, rather than iterating. If you use itertools, this is more efficient (and keeps the dicts you're working with in one place):

import itertools
[i
 for k, v in itertools.chain.from_iterable(d.iteritems() for d in (dict1, dict2))
 for i in [k] + (v or [])
 if i]

Thanks to Martijn Pieters for the from_iterable tip.

like image 77
kevingessner Avatar answered Mar 25 '26 23:03

kevingessner


The following line gives you what you want in as efficient a manner as possible, albeit a little verbose:

from itertools import chain, ifilter

list(ifilter(None, dict1.viewkeys() | dict2.viewkeys() | set(chain(chain.from_iterable(ifilter(None, dict1.itervalues())), chain.from_iterable(ifilter(None, dict2.itervalues()))))))

You could break it down to:

values1 = chain.from_iterable(ifilter(None, dict1.itervalues()))
values2 = chain.from_iterable(ifilter(None, dict2.itervalues()))
output = list(ifilter(None, dict1.viewkeys() | dict2.viewkeys() | set(chain(values1, values2))))

ifilter with a None filter removes false-y values such as None and '' from the iterable. the outer filter is not needed for your specific input but would remove '' and None if used as keys as well. Duplicate values are removed.

Ordering in Python dictionaries is arbitrary so ordering doesn't match your sample but all expected values are there.

Demo:

>>> list(ifilter(None, dict1.viewkeys() | dict2.viewkeys() | set(chain(chain.from_iterable(ifilter(None, dict1.itervalues())), chain.from_iterable(ifilter(None, dict2.itervalues()))))))
['313115', '305403', '313113', '311957', '253036', '12345']
like image 41
Martijn Pieters Avatar answered Mar 25 '26 21:03

Martijn Pieters



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!