carte blanche
carte blanche

Reputation: 11476

Combining two dicts into a list

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

Upvotes: 3

Views: 240

Answers (3)

Bleeding Fingers
Bleeding Fingers

Reputation: 7129

[each
 if isinstance(each,  str) else each[0]
 for pair in dict(dict1, **dict2).iteritems()
 for each in pair
 if each not in [[''], None, []]]

Upvotes: 0

kevingessner
kevingessner

Reputation: 18985

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.

Upvotes: 5

Martijn Pieters
Martijn Pieters

Reputation: 1123570

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

Upvotes: 1

Related Questions