How to unit a sequence of dicts in Python - python

I want to unit two dicts, but there are 10 dicts in a list, so how can I unit two by two without duplication?
I wrote something like this:
d_a1 = dict(list(dicts[0].items()) + list(dicts[1].items()))
d_b1 = dict(list(dicts[2].items()) + list(dicts[3].items()))
d_b2 = dict(list(dicts[4].items()) + list(dicts[5].items()))
d_b3 = dict(list(dicts[6].items()) + list(dicts[7].items()))
d_b4 = dict(list(dicts[8].items()) + list(dicts[9].items()))

You could use:
for d1, d2 in zip(dicts[::2], dicts[1::2]):
new_dict = dict(d1, **d2)
This pairs up the dictionaries and creates a new dictionary based on the two input dictionaries.
Further bringing this down to a loop with some iteration magic:
paired = [dict(d1, **d2) for d1, d2 in zip(*[iter(dicts)]*2)]
which produces a list of paired dictionaries.

This creates a list of all paired dictionaries:
it = iter(dicts)
paired_dicts = [dict(x, **next(it)) for x in it]

I would use:
import collections
newDicts = collections.deque((d1.update(d2) for d1,d2 in zip(*[iter(listOfDicts)]*2)), maxlen=0)
This should edit your dictionaries in-place. Thus, all the dictionaries in even numbered indices in your list of dictionaries would contain the union of itself and the dictionary in the very next index

Related

Combining a list and multiple dictionaries to nested dictionary - python

I want to create a nested dictionary out of a list that should be the keys and dictionaries that are the values of that nested dict.
Input:
l = [key1, key2, key3]
d1 = {string11:value11, string12:value12, string13:value13}
d2 = {string21:value21, string22:value22, string23:value23}
d3 = {string31:value31, string32:value32, string33:value33}
Output:
{key1 : {string11:value11, string12:value12, string13:value13}, key2 : {string21:value21, string22:value22, string23:value23}, key3 : {string31:value31, string32:value32, string33:value33}}
So far, I tried to zip the list and a dict but this creates another dict, not a nested dict.
ld = dict(zip(l,d))
Do I need to create a list of d1,d2,d3 first? How can I combine l and the list of dicts then?
Yes you'll need to create the list of d first
dict(zip(l, [d1, d2, d3]))
When you pass a dictionary in as an iterator, its values will be iterated over (The keys won't be included). Hence why dict(zip(l, d1)) will produce a single dictionary rather than a nested one.
There are many ways. You could for example use dict comprehension:
ld = {k: d for k, d in zip(l, [d1, d2, d3])}

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

How can you return the length of the number of distinct keys in a list of dictionaries without including keys that have already been seen?

self.dl = ({'a':1, 'b': 2, 'c': 3}, {'c':13, 'd':14, 'e':15}, {'e':25, 'f':26, 'g':27})
I have this tuple of dictionaries and am trying to get the count of all the distinct keys. I am only able to do this so that all the keys are counted. The output here should be 7 but I am getting 9 because c and e are being counted twice.
I have this so far:
new = []
for d in self.dl:
for k in d:
new.append(k)
return len(new)
from operator import or_ as union
from functools import reduce
len(reduce(union, map(dict.keys, self.dl)))
The view returned by keys() already acts like a set. So if you take the union (or_) of all the key sets from your dicts, you get the set of all keys. The length of that set is the number of unique keys.
You could probably try something like this:
new = {}
for d in self.dl:
for k in d:
if k not in new:
new[k] = 1
return len(new)
sets are definitely the data structure you want here. There are a few different ways you can accumulate the set:
new = set(k for d in self.dl for k in d)
or
from itertools import chain
new = set(chain(*self.dl))
or
new = set()
for d in self.dl:
new &= d.keys()
In all cases, len(new) will be the number of unique keys.

merge two lists of dictionaries in python?

I have two lists of dictionaries:
old = [{'a':'1','b':'2'},{'a':'2','b':'3'},{'a':'3','b':'4'},{'a':'4','b':'5'}]
new = [{'a':'1','b':'100'},{'a':'2','b':'100'},{'a':'5','b':'6'}]
How can I merge two lists of dictionaries to get:
update = [{'a':'1','b':'2,100'},{'a':'2','b':'3,100'},{'a':'3','b':'4'},{'a':'4','b':'5'},{'a':'5','b':'6'}]
the idea is if new 'a' is not in the old, add it and if new 'a' is in the old, update 'b' and if old 'a' is not in the new, keep it.
If 'a' is the real key here and b is the value, imo it would be easier to convert the list of dicts into one dict, process the merge and then convert it back. This way you can use the standard functions.
Convert into one dict where a is the key:
def intoRealDict(listOfDicts):
values = []
for item in listOfDicts:
values.append((item.get('a'), item.get('b')))
return dict(values) #Use Dict Constructur ('3', '4) -> {'3': '4'}
Convert into the data structure again:
def intoTheDataStructure(realDict):
res = []
for i in realDict:
res.append(dict([('a', i), ('b', realDict[i])]))
return res
Easy Merge of your two lists:
def merge(l1, l2):
d1, d2 = intoRealDict(l1), intoRealDict(l2)
for i in d2:
if i in d1:
#extend "b"
d1[i] = d1[i] + ", " + d2[i]
else:
#append value of key i
d1[i] = d2[i]
return intoTheDataStructure(d1)
Working Code with bad performance

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