Combining two dicts into a list - 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']

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.

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

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

Related

Splitting a dictionary by key suffixes

I have a dictionary like so
d = {"key_a":1, "anotherkey_a":2, "key_b":3, "anotherkey_b":4}
So the values and key names are not important here. The key (no pun intended) thing, is that related keys share the same suffix in my example above that is _a and _b.
These suffixes are not known before hand (they are not always _a and _b for example, and there are an unknown number of different suffixes.
What I would like to do, is to extract out related keys into their own dictionaries, and have all generated dictionaries in a list.
The output from above would be
output = [{"key_a":1, "anotherkey_a":2},{"key_b":3, "anotherkey_b":4}]
My current approach is to first get all the suffixes, and then generate the sub-dicts one at a time and append to the new list
output = list()
# Generate a set of suffixes
suffixes = set([k.split("_")[-1] for k in d.keys()])
# Create the subdict and append to output
for suffix in suffixes:
output.append({k:v for k,v in d.items() if k.endswith(suffix)})
This works (and is not prohibitively slow or anyhting) but I am simply wondering if there is a more elegant way to do it with a list or dict comprehension? Just out of interest...
Make your output a defaultdict rather than a list, with suffixes as keys:
from collections import defaultdict
output = defaultdict(lambda: {})
for k, v in d.items():
prefix, suffix = k.rsplit('_', 1)
output[suffix][k] = v
This will split your dict in a single pass and result in something like:
output = {"a" : {"key_a":1, "anotherkey_a":2}, "b": {"key_b":3, "anotherkey_b":4}}
and if you insist on converting it to a list, you can simply use:
output = list(output.values())
You could condense the lines
output = list()
for suffix in suffixes:
output.append({k:v for k,v in d.items() if k.endswith(suffix)})
to a list comprehension, like this
[{k:v for k,v in d.items() if k.endswith(suffix)} for suffix in suffixes]
Whether it is more elegant is probably in the eyes of the beholder.
The approach suggested by #Błotosmętek will probably be faster though, given a large dictionary, since it results in less looping.
def sub_dictionary_by_suffix(dictionary, suffix):
sub_dictionary = {k: v for k, v in dictionary.items() if k.endswith(suffix)}
return sub_dictionary
I hope it helps

Use A Single Line To Loop Two Dictionaries To Create List

I have looked at several threads similar but unable to get a workable solution. I am looping (2) dictionaries trying to create a single list from the values of one based on the keys of another. I have it done with for loops but looking to use a single line if possible. My code with for loops
for k, v in dict1.items():
for value in dict2[k]:
temp.append(value)
On the first loop thru the temp list would be and is from above code:
[16,18,20,22,24,26]
I then use min to get the min value of the list. Now I want to condense the for loop to a one liner. I have put together
temp=[dict2.values() for k in dict1.keys() if k in dict2.keys()]
When executed, instead of temp being a single list for the k that exist in the dict1, I get a list of list for all the values from all dict2.
[[16,18,20,22,24,26], [12,16,18,20,22,24], [16,18,22,26,30,32]]
It seems to be ignoring the if statement. I know my dict1 has only 1 key in this situation and I know the 1 key exist in the dict2. Is my one liner wrong?
Input Values for dictionaries:
dict1={'table1':[16,18,20,22,24,26]}
dict2={'table1':[16,18,20,22,24,26],'table2': [12,16,18,20,22,24], 'table3': [16,18,22,26,30,32]}
You can iterate through one dictionary checking for matching keys and create a list of lists. Use chain.from_iterable to flatten list and call min():
from itertools import chain
dict1 = {'table1': [16,18,20,22,24,26]}
dict2 = {'table1': [16,18,20,22,24,26], 'table2': [12,16,18,20,22,24], 'table3': [16,18,22,26,30,32]}
temp = [dict2[k] for k in dict1 if k in dict2]
print(min(chain.from_iterable(temp)))
# 16
The reason why your list comprehension does not work:
It looks like dict2 has 3 key-value pairs, and the values are [16,18,20,22,24,26], [12,16,18,20,22,24]and [16,18,22,26,30,32]. What you're doing in your list comprehension translates to
for k in dict1.keys():
if k in dict2.keys():
temp.append(dict2.values())
So if dict1has, let's say, 3 keys, this for loop will repeat 3 times. Because, as you said in a comment above, only one key is shared between dict1and dict2, the if statement only is True once, so all items of dict2.values() will be appended to temponce. What you want to do, if i got that right, is to append all items INSIDE one of the values of dict2, namely the one assigned to the one key that the two dicts share. Your idea was pretty close, you just have to add one little thing. As a one liner, it would look like this:
temp = [x for x in dict2[k] for k in dict1.keys() if k in dict2.keys()]
or, differently:
temp = [dict2[k] for k in set(dict1.keys()).intersection(set(dict2.keys()))]
You can use the operator itemgetter():
from operator import itemgetter
from itertools import chain
dict1 = {'table1': [16,18,20,22,24,26], 'table2': [12,16,18,20,22,24]}
dict2 = {'table1': [16,18,20,22,24,26], 'table2': [12,16,18,20,22,24], 'table3': [16,18,22,26,30,32]}
common_keys = set(dict1).intersection(dict2)
sublists = itemgetter(*common_keys)(dict2)
if len(common_keys) == 1:
max_val = max(sublists)
else:
max_val = max(chain.from_iterable(sublists))
print(max_val)
# 26

Parsing list items and returning a dictionary using comprehension

I have a two-items list which I need to process. Those items are retrieved from a database, so the are actually header: value pairs but they are unparsed. They are strings separated by tabs, so the list looks like this:
my_list = ['header1\theader2\theader3\theader4', 'val1\tval2\tval3\tval4']
I need to create dict from the key - value pairs. Currently I do it with list comprehension:
keys = [k.strip() for k in my_list[0].split('\t')]
vals = [v.strip() for v in my_list[1].split('\t')]
return dict(zip(keys, vals))
I think there might be a way doing that using dict comprehension instead, but I couldn't get how. Is it possible to do parse the list items and return a dictionary with a one-liner or a more pythonic way?
I find the solution below the most elegant one:
dict_comp = dict(zip(*map(lambda x: x.split('\t'), my_list)))
print(dict_comp) # -> {'header1': 'val1', 'header2': 'val2', 'header3': 'val3', 'header4': 'val4'}
Alternatively, the lambda can be substituted by a generator expression:
dict_comp = dict(zip(*(x.split('\t') for x in my_list)))
and if the strings do not contain any spaces, it can be shortened even further to:
dict_comp = dict(zip(*map(str.split, my_list))) # kudos #Chris_Rands
Try something like this
dict_comp = {k.strip():v.strip() for k,v in
zip(my_list[0].split('\t'), my_list[1].split('\t'))}

Filtering a dictionary value from a list of dictionary using lambda and filter in python

I have a list of dictionaries as below:
l = [{'abc': 'def'}, {'ghi': 'jul'}, {'Name': 'my-name'}]
I want to get the value of the dictionary that has the key 'Name'
Initially I wrote a function as below:
def get_json_val(l, key):
for item in l:
for k, v in item.iteritems():
if k == key:
return v
But I want to do it using lambdas and filter in a single line. So, I tried as below to filter out the dictionary:
name_lst = filter(lambda item: (k == 'Name' for k in item.iteritems()), l)
It is showing the whole list again. Is there a way to get only the value (not dictionary) using lambdas and filter? Thanks in advance
Edit 1:
In the first function l is list and 'Name' is passed as key.
Seeing your initial code, this should do the same thing
>>> l = [{'abc': 'def'}, {'ghi': 'jul'}, {'Name': 'my-name'}]
>>> [i["Name"] for i in l if "Name" in i][0]
'my-name'
Your code returns only the first occurence.Using my approach, and probably also if you would use filter, you'll get (first) a list of all occurrences than only get the first (if any). This would make it less "efficient" IMHO, so I would probably change your code to be something more like this:
def get_json_val(l, key):
for item in l:
if not key in item: continue
return item[key]
Why are you iterating over your dict? That defeats the purpose. Just do
[d for d in l if key in d]
Or if you feel some compulsion to use lambda and filter:
filter(lambda d: key in d, l)
Note, these return lists instead of the corresponding value. If you want the value, you'll have to index into the list. Simply out, using a loop is probably the most reasonable approach, just don't iterate over your dict:
def f(key, l):
for d in l:
if key in d:
return d[key]
l = [{'abc': 'def'}, {'ghi': 'jul'}, {'Name': 'my-name', "no-name": "bbb"}]
I was able to do it in this way,
print filter(lambda item: item, map(lambda item: item.get("Name"), l))
if I break this down.
First check if item is in the dict or not?
fna = lambda item: item.get("Name")
then map list of dict to above function.
map(fna, l)
for above list it will print
[None, None, 'my-name']
Now we need to eliminate all the None. I am using filter with following function
fnb = lambda item: item
Now if you put all together you have your code in single line.
Here is an easy way to do it without lambdas or filter or any of that stuff. Just combine the list of dictionaries to one dictionary, then use that.
l = [{'abc': 'def'}, {'ghi': 'jul'}, {'Name': 'my-name'}]
k = {m.keys()[0] : m[m.keys()[0]] for m in l}['Name']
Note that this does not change the structure of l.
Don't underestimate the power of dict.get(). What follows is a simplification of a previous answer. In this case, there is no need for map. For the list:
l = [{'abc': 'def'}, {'ghi': 'jul'}, {'Name': 'my-name'}]
The following produces a list of dictionaries that have the key 'Name':
filtered = list(filter(lambda x: x.get('Name'), l))
From here, you can retrieve the name values for all items in the list:
values = [x['Name'] for x in filtered]
If there is only one target, as in your example, wrap this all up in one line like this:
name = list(filter(lambda x: x.get('Name'), l))[0]['Name']

Returning unique elements from values in a dictionary

I have a dictionary like this :
d = {'v03':["elem_A","elem_B","elem_C"],'v02':["elem_A","elem_D","elem_C"],'v01':["elem_A","elem_E"]}
How would you return a new dictionary with the elements that are not contained in the key of the highest value ?
In this case :
d2 = {'v02':['elem_D'],'v01':["elem_E"]}
Thank you,
I prefer to do differences with the builtin data type designed for it: sets.
It is also preferable to write loops rather than elaborate comprehensions. One-liners are clever, but understandable code that you can return to and understand is even better.
d = {'v03':["elem_A","elem_B","elem_C"],'v02':["elem_A","elem_D","elem_C"],'v01':["elem_A","elem_E"]}
last = None
d2 = {}
for key in sorted(d.keys()):
if last:
if set(d[last]) - set(d[key]):
d2[last] = sorted(set(d[last]) - set(d[key]))
last = key
print d2
{'v01': ['elem_E'], 'v02': ['elem_D']}
from collections import defaultdict
myNewDict = defaultdict(list)
all_keys = d.keys()
all_keys.sort()
max_value = all_keys[-1]
for key in d:
if key != max_value:
for value in d[key]:
if value not in d[max_value]:
myNewDict[key].append(value)
You can get fancier with set operations by taking the set difference between the values in d[max_value] and each of the other keys but first I think you should get comfortable working with dictionaries and lists.
defaultdict(<type 'list'>, {'v01': ['elem_E'], 'v02': ['elem_D']})
one reason not to use sets is that the solution does not generalize enough because sets can only have hashable objects. If your values are lists of lists the members (sublists) are not hashable so you can't use a set operation
Depending on your python version, you may be able to get this done with only one line, using dict comprehension:
>>> d2 = {k:[v for v in values if not v in d.get(max(d.keys()))] for k, values in d.items()}
>>> d2
{'v01': ['elem_E'], 'v02': ['elem_D'], 'v03': []}
This puts together a copy of dict d with containing lists being stripped off all items stored at the max key. The resulting dict looks more or less like what you are going for.
If you don't want the empty list at key v03, wrap the result itself in another dict:
>>> {k:v for k,v in d2.items() if len(v) > 0}
{'v01': ['elem_E'], 'v02': ['elem_D']}
EDIT:
In case your original dict has a very large keyset [or said operation is required frequently], you might also want to substitute the expression d.get(max(d.keys())) by some previously assigned list variable for performance [but I ain't sure if it doesn't in fact get pre-computed anyway]. This speeds up the whole thing by almost 100%. The following runs 100,000 times in 1.5 secs on my machine, whereas the unsubstituted expression takes more than 3 seconds.
>>> bl = d.get(max(d.keys()))
>>> d2 = {k:v for k,v in {k:[v for v in values if not v in bl] for k, values in d.items()}.items() if len(v) > 0}

Categories