merge to dictionaries preserving different values - python

I am very new to python (python 3.2) and I have been struggling with a difficult problem. I have two dictionary with listed lists:
d1 = {
'mammals': ['dog', '5', 'cat', '4', 'mouse', '4', 'bat', '3'],
'bird': ['robin', '8', 'bluejay', '6', 'goose', '5', 'cardinal', '5']
}
and
d2 = {
'mammals': ['cow', '5', 'horse', '4', 'cat', '4', 'dog', '3', 'beaver', '3'],
'bird': ['bluejay', '9', 'goose', '8', 'eagle', '8', 'robin', '7', 'duck', '6', 'cardinal', '5']
}
In each dictionary, the pair name-number (for instance, 'dog', '5') correspond to how many instances of said item where present in the original data bases.
What I need is to merge the two dictionaries in a way that information about quantity preserved (again, in the example, the new dictionary would have 'dog', '5', '3'. So that the merged dictionary would look somewhat like (I am not necessarily committed to nested dictionaries. I wrote it this way for easiness of visualization. The important thing is too keep the information):
d_merged = {
'mammals': [{'dog': ['5', '3']}, {'cat': ['4', '4']}, {'mouse': '4'}, {'bat': '3'} , {'cow': '5'},
{'horse': '4'}, {'beaver': '3'}],
'bird': [{'robin': ['8', '7']}, {'bluejay': ['6', '9']}, {'goose': ['5','8']}, {'cardinal': ['5',
'5']}, {'eagle': '8'}, {'duck', '6'}]
}
I have tried various things with tuples, nested dictionaries and other possibilities, but the result has been a mess. It would mean a lot if someone could point me in a good direction to solve this. I thank you very much

The most readable way to do it is probably as follows:
output = {}
for key in d1.keys():
output[key] = {}
lst = d1[key]
for name, count in (lst[i:i+2] for i in range(0, len(lst), 2)):
output[key][name] = (int(count),)
for key in d2.keys():
if key not in output:
output[key] = {}
lst = d2[key]
for name, count in (lst[i:i+2] for i in range(0, len(lst), 2)):
if name in output[key].keys():
output[key][name] += (int(count),)
else:
output[key][name] = (int(count),)
In incomprehensible dictionary comprehensions, you can do it in two steps
d = {k: {a: int(b) for a, b in (v[i:i+2] for i in range(0, len(v), 2))}
for k, v in d.items()}
To turn them into dictionaries of dictionaries, e.g.
{'mammals': {'cat': 4, 'cow': 5, 'dog': 3, 'beaver': 3, 'horse': 4},
'bird': {'goose': 8, 'duck': 6, 'eagle': 8, 'bluejay': 9, 'robin': 7, 'cardinal': 5}}
Then
output = {k1: {k2: (d1.get(k1, {}).get(k2), d2.get(k1, {}).get(k2))
for k2 in set(list(d1.get(k1, {}).keys()) + list(d2.get(k1, {}).keys()))}
for k1 in set(list(d1.keys()) + list(d2.keys()))}
To combine the two.
Note that these methods both work even if there are different keys at the two levels (e.g. adding d1['reptiles'] = {'lizard': 10}).

first you can change d1 and d2 to be dictionaries that is easier to work with:
[note that list[::2] is sublist that holds all the item in the even indices, and list[1::2] holds the odds.]
>>> dc1 = {}
>>> for family in d1.keys():
l = d1[family]
dc1[family] = {l[::2][family]:[l[1::2][family]] for family in range(len(l)/2)}
>>> dc2 = {}
>>> for family in d1.keys():
l = d2[family]
dc2[family] = {l[::2][family]:[l[1::2][family]] for family in range(len(l)/2)}
now dc1 and dc2 are these:
>>> dc1
{'mammals': {'bat': ['3'], 'mouse': ['4'], 'dog': ['5'], 'cat': ['4']},
'bird': {'goose': ['5'], 'cardinal': ['5'], 'robin': ['8'], 'bluejay': ['6']}}
>>> dc2
{'mammals': {'beaver': ['3'], 'horse': ['4'], 'dog': ['3'], 'cow': ['5'], 'cat': ['4']},
'bird': {'eagle': ['8'], 'bluejay': ['9'], 'goose': ['8'], 'cardinal': ['5'], 'duck': ['6'], 'robin': ['7']}}
and then you just need to combine them
>>> d_merged = {}
>>> families = set(d1.keys()+d2.keys())
>>> family2animals = {family:list(set(dc1[family].keys()+dc2[family].keys())) for family in families}
>>> for family in families:
d_merged[family] = [{animal:dc1[family].get(animal,[])+dc2[family].get(animal,[])} for animal in family2animals[family]]

Related

Convert values from list of dictionaries from string to integer

I have a list of 54 dictionaries, formatted as so:
[{'1A': '1',
'3E': '2',
'PRODUCT NUMBER': '1',
'Week': '1'}
,
{'1A': '1',
'1B': '1',
'1C': '1',
'1D': '2',
'1E': '2',
'2C': '1',
'3E': '2',
'PRODUCT NUMBER': '2',
'Week': '1'},...] and etc
I am trying to convert the values from strings to integers.
I have successfully managed to do this for my very last dictionary, but it doesnt seem to be working for the rest.
This is my code:
for i in buyers: #buyers is the list
for n in buyers_dict: # the code works without this line the same, i cant figure out where to implement the 'n'
for k, v in buyers_list.items():
buyers_list[k] = int(v)
pprint.pprint(buyers)
Like I said, the 54th dictionary values are converted, but the rest are still strings
here is my excel file:
I've then condensed the dictionaries to just contain the key values pairs that have a value. Now I need to convert the values into integers.
Assuming your data is in this schema:
buyers = [{...}, {...}, ...]
You need to loop through the list of dicts then work on those dicts in particular:
for d in buyers:
for k, v in d.items():
d[k] = int(v)
Or in comprehension form:
buyers = [{k: int(v) for k, v in d.items()} for d in buyers]
d=[{'1A': '1',
'3E': '2',
'PRODUCT NUMBER': '1',
'Week': '1'}]
Using Comprehension
[{k:int(v)} for i in d for (k,v) in i.items() ]
Output:
[{'1A': 1}, {'3E': 2}, {'PRODUCT NUMBER': 1}, {'Week': 1}]

How can I remove a value in this list if it is not inside one of the keys of this nested dictionary?

Currently, I have the following weird nested dictionary:
d = {'start': {'0': {'start', 'near'}, '1': {'start'}}, 'near': {'1': {'end'}}, 'end': {}}
And the following list:
l = ['1', '0', '1', 'x', '0', '1']
If one of the values in l are not in one of the keys and values in the dictionary, remove it from the list.
So for example, in the list, there is an "x" and I am trying to see if there is anyway I can remove it with either l.remove() or if del / pop is better.
The thing that is giving me troubles is the dictionary.
What I have going so far:
d = {'start': {'0': {'start', 'near'}, '1': {'start'}}, 'near': {'1': {'end'}}, 'end': {}}
l = ['1', '0', '1', 'x', '0', '1']
for key, value in d.items():
for keys, values in value.items():
for number in l:
Get the set of keys:
keys = set.union(*[set(x.keys()) for x in d.values()])
#{'0', '1'}
Filter out the non-keys:
result = [item for item in l if item in keys]
#['1', '0', '1', '0', '1']

Compare two lists which are values in a dict and return which has the min val in the list Python

I have a dict like this
b = {'2': ['10', '5', '4'], '4': ['1', '9', '2'], '3': ['90', '87', '77'], '1': ['30']}
I need to compare each value in the list to others and return only the least value in the dict
I have tried
for k,v in b.items():
for r in range(len(v)):
print(min(v[r] + v[r]))
It is giving me a weird output!
This is the output obtained from that code.
0
5
4
1
9
2
0
7
7
0
0
0
0
I need the key and value which has the least value in the entire dict output like this d = {4:[1]}
Ugly one-liner:
b = {'2': ['10', '5', '4'], '4': ['1', '9', '2'], '3': ['90', '87', '77'], '1': ['30']}
result = dict([min(((int(k), [min(map(int, v))]) for k, v in b.items()), key=lambda t: t[1])])
print(result)
Output:
{4: [1]}
Breakdown:
b = {'2': ['10', '5', '4'], '4': ['1', '9', '2'], '3': ['90', '87', '77'], '1': ['30']}
# Generator of each key with its minimal element
# (here the generator would produce the list [(2, [4]), (4, [1]), (3, [77]), (1, [30])])
key_min = ((int(k), [min(map(int, v))]) for k, v in b.items())
# Pick tuple with minimal value
# (here the tuple (4, [1]) from the previous generator)
min_entry = min(key_min, key=lambda t: t[1])
# Make into dict
# (here {4: [1]}; first element of the tuple is the key and second element the value)
result = dict([min_entry])
print(result)
You can do it with a dict-comprehension
{int(key): [min( int(value) for value in value_list)] for key, value_list in b.items()}
If you want a straightforward answer without any confusion
min_list = {}
for k,v in b.items():
min_value = min(v)
min_list[min_value] = k
print({ min_list[min(min_list)]:min(min_list)})
You want the minimum of minimums, or:
min({k: min(b[k], key=int) for k in b}.items(), key=lambda x: x[1])
This returns the tuple ('4', '1').
First, your list is numbers as text. I did not correct that. If you can fix that then you can take off the in() in this code.
for k, v in b.items():
x = int(min(b[k]))
try:
lowVal
except:
lowVal = x
lowKey = k
else:
if x < lowVal:
lowKey = k
lowVal = x
print('{0}: {1}'.format(lowKey, lowVal))
Step through each item in the dict
find the lowest value and make it an int() and set to x for convenience
try to see if this is our first time through, if it is set the key to lowKey and the lowest value in the list to lowVal
Otherwise if lowVal already exists see if the current lowest value in the list is lower than the previous lowest. If it is then set lowKey and lowVal to the current loops values
Print
????
Profit
Edit: a word
What if you have multiple key value pairs with same minimum value?
This solution works fine for that as well.
result={k:min(map(int,v)) for k,v in b.items()}
minVal=min(result.values())
result={k:[minVal] for k in result.iterkeys() if result[k] == minVal}
print(result)
{'4': [1]}
for ex :
b = {'2': ['10', '5', '4'], '4': ['1', '9', '2'], '3': ['90', '1', '77'], '1': ['30']}
Output will be :
{'3': [1], '4': [1]}

create a list of dictionaries from two lists of tuples

I have a set of tuples:
users = set(("test#a.com","password"),("test#b.com","password"))
but could be simplified to a set...and a list of tuples:
licences = [("test#a.com","22"),("test#a.com","23"),("test#b.com","12")]
For every entry of the list the username could be repeated with different "licence" values.
I need to build a list of dictionaries like this:
[{"user":"test#a.com", "licences":["22","23"]},{"user":"test#b.com", "licences":["12"]}]
What I've done so far is this:
licenzadiz = []
for num,user in enumerate(users):
licenzadiz.append({'user': user[0], 'licences': []})
for num2,licence in enumerate(licences):
if user[0] == licence[0]:
licenzadiz[num]['licences'].append(licence[1])
that is working well. BUT I wonder if there are more elegant solutions to my problem.
You can get fancy with nested default dicts:
from collections import defaultdict
items = [('A','1'),('A','3'),('A','2'),
('B','0'),('B','4'),('B','-1'),
('C','7'),('C','6'),('C','12')]
d = defaultdict(lambda: defaultdict(list))
for use,lic in items:
d[use]['username'] = use #<-- Overwrites each time an already known key is found, but thats ok
d[use]['licence'].append(lic)
#Just for printout
for use in d:
print d[use]
print d[use]['username']
print d[use]['licence']
Output:
defaultdict(<type 'list'>, {'username': 'A', 'licence': ['1', '3', '2']})
A
['1', '3', '2']
defaultdict(<type 'list'>, {'username': 'C', 'licence': ['7', '6', '12']})
C
['7', '6', '12']
defaultdict(<type 'list'>, {'username': 'B', 'licence': ['0', '4', '-1']})
B
['0', '4', '-1']
data = {}
for num2,(email, license) in enumerate(licenze):
data.setdefault(email,[]).append(license)
print data #dictionary of email:[licenses,..]
#or
print data.items() # if you want a list
I guess ... i think

split a key in a dic and its values to multiple keys/values

I have the following dic:
dic = {'shape': ['a', 'b', 'c'], 'item1_item2_item3': ['1_2_3', '5_6_10', '3_7_9']}
I want to convert it to:
dic = {'shape': ['a', 'b', 'c'], 'item1': ['1', '2', '3'], 'item2': ['5', '6', '10'], 'item3': ['3', '7', '9']}
Basically, I want to split based on '_' and make new keys/values out of the original key and its values.
The size of the second key might have more items; for example 'item1_item2,item3,item4'.
Use zip() to pair up the split key and values; you'll want to build a new dictionary here:
new = {}
for key, value in dic.items():
if '_' not in key:
new[key] = value
continue
for new_key, new_value in zip(key.split('_'), value):
new[new_key] = new_value.split('_')
You could mash this in to a dictionary comprehension but it becomes rather harder to follow:
{nk: (nv.split('_') if '_' in k else v)
for k, v in dic.items() for nk, nv in zip(k.split('_'), v)}
Demo:
>>> dic = {'shape': ['a', 'b', 'c'], 'item1_item2_item3': ['1_2_3', '5_6_10', '3_7_9']}
>>> new = {}
>>> for key, value in dic.items():
... if '_' not in key:
... new[key] = value
... continue
... for new_key, new_value in zip(key.split('_'), value):
... new[new_key] = new_value.split('_')
...
>>> new
{'item2': ['5', '6', '10'], 'item3': ['3', '7', '9'], 'shape': ['a', 'b', 'c'], 'item1': ['1', '2', '3']}
>>> {nk: (nv.split('_') if '_' in k else v)
... for k, v in dic.items() for nk, nv in zip(k.split('_'), v)}
{'item2': ['5', '6', '10'], 'item3': ['3', '7', '9'], 'shape': ['a', 'b', 'c'], 'item1': ['1', '2', '3']}
What you wanna do it's this:
Extract the key that you wanna split
split it and assign it to a new list
assing the values of the key to a list of the new list and append it to the new key
delete the old key and value
To get you started
dic = {item: "whatever", item1_item2_item3: [1,2,3], [2,3,4]. [4,5,6]}
copy = dic[item1_item2_item3]
name = item1_item2_item3
name = name.split("_")
#this make a list like this: [item1, item2, item3]
for i in len(name):
dic[name[i]] = copy[i]
del.dic[item1_item2_item3]
You can split string using my_string.split("_") to get a list strings. Here's one solution to split the strings and the keys and assign the new values:
dic = {'shape': ['a', 'b', 'c'], 'item1_item2_item3': ['1_2_3', '5_6_10', '3_7_9']}
new_dic = {}
for k in dic.keys():
val = dic[k]
subkeys = k.split("_")
if len(subkeys) > 1:
for s in range(len(subkeys)):
subkey = subkeys[s]
subvals = val[s].split("_")
new_dic[subkey] = subvals
# this handles the case where the key has no underscores
else:
new_dic[k] = val
print new_dic

Categories

Resources