Combining dictionaries within dictionaries & adding values - python

I am trying to combine two dictionaries to yield a result like this:
a = {"cat": 3, "dog": 4, "rabbit": 19, "horse": 3, "shoe": 2}
b = {"cat": 2, "rabbit": 1, "fish": 9, "horse": 5}
ab = {"cat": 5, "dog": 4, "rabbit": 20, "horse": 8, "shoe": 2, "fish": 9}
So that if they have the same keys, the values will be added, if one key is present in one dictionary but not the other, it will add it to the new dictionary with its corresponding value.
These two dictionaries are also both nested in separate dictionaries as well such that:
x = {'a': {"cat": 3, "dog": 4, "rabbit": 19, "horse": 3, "shoe": 2}, 'c': blah, 'e': fart}
y = {'a': {"cat": 2, "rabbit": 1, "fish": 9, "horse": 5}, 'c': help, 'e': me}
The keys are the same in both main dictionaries.
I have been trying to combine the two dictionaries:
def newdict(x,y):
merged= [x,y]
newdict = {}
for i in merged:
for k,v in i.items():
new.setdefault(k,[]).append(v)
All this gives me is a dictionary with values belonging to the same keys in a list. I can't figure out how to iterate through the two lists for a key and add the values together to create one joint dictionary. Can anyone help me?
End result should be something like:
xy = {'a' = {"cat": 5, "dog": 4, "rabbit": 20, "horse": 8, "shoe": 2, "fish": 9}, 'c': blah, 'e': me}
The 'c' and 'e' keys I will have to iterate through and perform a different calculation based on the results from 'a'.
I hope I explained my problem clearly enough.

My attempt would be:
a = {"cat": 3, "dog": 4, "rabbit": 19, "horse": 3, "shoe": 2}
b = {"cat": 2, "rabbit": 1, "fish": 9, "horse": 5}
def newdict(x, y):
ret = {}
for key in x.keys():
if isinstance(x[key], dict):
ret[key] = newdict(x[key], y.get(key, {}))
continue
ret[key] = x[key] + y.get(key, 0)
for key in y.keys():
if isinstance(y[key], dict):
ret[key] = newdict(y[key], x.get(key, {}))
continue
ret[key] = y[key] + x.get(key, 0)
return ret
ab = newdict(a, b)
print ab
> {'horse': 8, 'fish': 9, 'dog': 4, 'cat': 5, 'shoe': 2, 'rabbit': 20}
Explanation:
The newdict function first iterates through the first dictionary (x). For every key in x, it creates a new entry in the new dictionary, setting the value to the sum of x[key] and y[key]. The dict.get function supplies an optional second argument that it returns when key isn't in dict.
If x[key] is a dict, it sets ret[key] to a merged dictionary of x[key] and y[key].
It then does the same for y and returns.
Note: This doesn't work for functions. Try figuring something out yourself there.

Using collections.Counter and isinstance:
>>> from collections import Counter
>>> from itertools import chain
>>> x = {'e': 'fart', 'a': {'dog': 4, 'rabbit': 19, 'shoe': 2, 'cat': 3, 'horse': 3}, 'c': 'blah'}
>>> y = {'e': 'me', 'a': {'rabbit': 1, 'fish': 9, 'cat': 2, 'horse': 5}, 'c': 'help'}
>>> c = {}
>>> for k, v in chain(x.items(), y.items()):
if isinstance(v, dict):
c[k] = c.get(k, Counter()) + Counter(v)
...
>>> c
{'a': Counter({'rabbit': 20, 'fish': 9, 'horse': 8, 'cat': 5, 'dog': 4, 'shoe': 2})}
Now based on the value of 'a' you can calculate the values for keys 'a' and 'e', but this time use: if not isinstance(v, dict)
Update: Solution using no imports:
>>> c = {}
>>> for d in (x, y):
for k, v in d.items():
if isinstance(v, dict):
keys = (set(c[k]) if k in c else set()).union(set(v)) #Common keys
c[k] = { k1: v.get(k1, 0) + c.get(k, {}).get(k1, 0) for k1 in keys}
...
>>> c
{'a': {'dog': 4, 'rabbit': 20, 'shoe': 2, 'fish': 9, 'horse': 8, 'cat': 5}}

To do it easily, you can use collections.Counter:
>>> from collections import Counter
>>> a = {"cat": 3, "dog": 4, "rabbit": 19, "horse": 3, "shoe": 2}
>>> b = {"cat": 2, "rabbit": 1, "fish": 9, "horse": 5}
>>> Counter(a) + Counter(b)
Counter({'rabbit': 20, 'fish': 9, 'horse': 8, 'cat': 5, 'dog': 4, 'shoe': 2})
So, in your case, it would be something like:
newdict['a'] = Counter(x['a']) + Counter(y['a'])
If you for some reason don't want it to be a Counter, you just pass the result to dict().
Edit:
If you're not allowed imports, you'll have to do the addition manually, but this should be simple enough.
Since this sounds like homework, I'll give you a few hints instead of a full answer:
create a collection of all keys, or loop over each dict(you can use a set to make sure the keys are unique, but duplicates shouldn't be a problem, since they'll be overwritten)
for each key, add the sum of values in the old dicts to the new dict(you can use dict.get() to get a 0 if the key is not present)

def newDict(a,b):
newD={}
for key in a:
newD[key]=a[key]
for key in b:
newD[key]=newD.get(key,0)+b[key]
return newD

My naive solution is:
a = {'a':'b'}
b = {'c':'d'}
c = {'e':'f'}
def Merge(n):
m = {}
for i in range(len(n)):
m.update({i+1:n[i]})
return m
print(Merge([a,b,c]))

Related

Add dictionary key-values to all keys of another dictionary

I am trying to add the value of a dictionary that has only one key to all keys of another dictionary but my dictionaries have different keys. I want to do that using a loop because my original dictionary has more than 100 keys.
Here is an example of the dictionaries (dict2 should be added to each key of dict1):
dict1 = {
'a': 3.84,
'b': 4.9,
'c': 6.7}
dict2={'value': {0: 1,
1: 6,
2: 10,
3: 2}}
For clarification, the dict2 should have only one key ('value'). The dict2 was created from a csv data frame, I tried to remove the line indexes but didn't find a way.
The "final" dictionary should have the value from dict1 and dict2 but without the "line indexes" of dict2. The final dictionary should look like this:
dict3 = {
'a': 3.84,
1,
6,
10,
2,
'b': 4.9,
1,
6,
10,
2,
'c': 6.7,
1,
6,
10,
2 }
I tried many ways to do that using append(), update() but it didn't work. I also tried to use the dict2 as an array but it didn't work too.
Thanks for any help!
You have to make the values for each key in dict3 a list since you can't have multiple values for one key. Here is a possible solution:
dict1 = {'a': 3.84, 'b': 4.9, 'c': 6.7}
dict2 = {'value': {0: 1, 1: 6, 2: 10, 3: 2}}
def dict_merge(dict1, dict2):
dict3 = {}
for key in dict1:
dict3[key] = [dict1[key]]
for key2 in dict2["value"]:
dict3[key].append(dict2["value"][key2])
return dict3
print(dict_merge(dict1, dict2))
Output:
{'a': [3.84, 1, 6, 10, 2], 'b': [4.9, 1, 6, 10, 2], 'c': [6.7, 1, 6, 10, 2]}
If you want to create a list for every dict1 key, you can use this:
dict2_values = dict2["value"].values()
dict3 = {k: [v, *dict2_values] for k, v in dict1.items()}
We used special syntax of iterable unpacking here
l1 = [1,2]
l2 = [3,4]
print([*l1, *l2, 5]) # [1,2,3,4,5]

Python Dictionary Filtration with items as a list

I have several lists as items in my dictionary. I want to create a dictionary with the same keys, but only with items that correspond to the unique values of the list in the first key. What's the best way to do this?
Original:
d = {'s': ['a','a','a','b','b','b','b'],
'd': ['c1','d2','c3','d4','c5','d6','c7'],
'g': ['e1','f2','e3','f4','e5','f6','e7']}
Output:
e = {'s': ['a','a','a'],
'd': ['c1','d2','c3'],
'g': ['e1','f2','e3']}
f = {'s': ['b','b','b','b'],
'd': ['d4','c5','d6','c7'],
'g': ['f4','e5','f6','e7']}
I don't think there is an easy way to do this. I created a (not so) little function for you:
def func(entry):
PARSING_KEY = "s"
# check if entry dict is valid (optional)
assert type(entry)==dict
for key in entry.keys():
assert type(entry[key])==list
first_list = entry[PARSING_KEY]
first_list_len = len(first_list)
for key in entry.keys():
assert len(entry[key]) == first_list_len
# parsing
output_list_index = []
already_check = set()
for index1, item1 in enumerate(entry[PARSING_KEY]):
if not item1 in already_check:
output_list_index.append([])
for index2, item2 in enumerate(entry[PARSING_KEY][index1:]):
if item2==item1:
output_list_index[-1].append(index2)
already_check.add(item1)
# creating lists
output_list = []
for indexes in output_list_index:
new_dict = {}
for key, value in entry.items():
new_dict[key] = [value[i] for i in indexes]
output_list.append(new_dict)
return output_list
Note that because of the structure of dict, there isn't a "first key" so you have to hardcode the key you want to use to parse (whit the "PARSING_KEY" constant at the top of the function)
original_dict = {
'a': [1, 3, 5, 8, 4, 2, 1, 2, 7],
'b': [4, 4, 4, 4, 4, 3],
'c': [822, 1, 'hello', 'world']
}
distinct_dict = {k: list(set(v)) for k, v in original_dict.items()}
distinct_dict
yields
{'a': [1, 2, 3, 4, 5, 7, 8], 'b': [3, 4], 'c': [1, 'hello', 'world', 822]}

merging two python dicts and keeping the max key, val in the new updated dict

I need a method where I can merge two dicts keeping the max value when one of the keys, value are in both dicts.
dict_a maps "A", "B", "C" to 3, 2, 6
dict_b maps "B", "C", "D" to 7, 4, 1
final_dict map "A", "B", "C", "D" to 3, 7, 6, 1
I did get the job half done but I didn't figure out how to keep the max value for the 'C' key, value pair.
Used itertools chain() or update().
OK so this works by making a union set of all possible keys dict_a.keys() | dict_b.keys() and then using dict.get which by default returns None if the key is not present (rather than throwing an error). We then take the max (of the one which isn't None).
def none_max(a, b):
if a is None:
return b
if b is None:
return a
return max(a, b)
def max_dict(dict_a, dict_b):
all_keys = dict_a.keys() | dict_b.keys()
return {k: none_max(dict_a.get(k), dict_b.get(k)) for k in all_keys}
Note that this will work with any comparable values -- many of the other answers fail for negatives or zeros.
Example:
Inputs:
dict_a = {'a': 3, 'b': 2, 'c': 6}
dict_b = {'b': 7, 'c': 4, 'd': 1}
Outputs:
max_dict(dict_a, dict_b) # == {'b': 7, 'c': 6, 'd': 1, 'a': 3}
What about
{
k:max(
dict_a.get(k,-float('inf')),
dict_b.get(k,-float('inf'))
) for k in dict_a.keys()|dict_b.keys()
}
which returns
{'A': 3, 'D': 1, 'C': 6, 'B': 7}
With
>>> dict_a = {'A':3, 'B':2, 'C':6}
>>> dict_b = {'B':7, 'C':4, 'D':1}
Here is a working one liner
from itertools import chain
x = dict(a=30,b=40,c=50)
y = dict(a=100,d=10,c=30)
x = {k:max(x.get(k, 0), y.get(k, 0)) for k in set(chain(x,y))}
In[83]: sorted(x.items())
Out[83]: [('a', 100), ('b', 40), ('c', 50), ('d', 10)]
This is going to work in any case, i.e for common keys it will take the max of the value otherwise the existing value from corresponding dict.
Extending this so you can have any number of dictionaries in a list rather than just two:
a = {'a': 3, 'b': 2, 'c': 6}
b = {'b': 7, 'c': 4, 'd': 1}
c = {'c': 1, 'd': 5, 'e': 7}
all_dicts = [a,b,c]
from functools import reduce
all_keys = reduce((lambda x,y : x | y),[d.keys() for d in all_dicts])
max_dict = { k : max(d.get(k,0) for d in all_dicts) for k in all_keys }
If you know that all your values are non-negative (or have a clear smallest number), then this oneliner can solve your issue:
a = dict(a=3,b=2,c=6)
b = dict(b=7,c=4,d=1)
merged = { k: max(a.get(k, 0), b.get(k, 0)) for k in set(a) | set(b) }
Use your smallest-possible-number instead of the 0. (E. g. float('-inf') or similar.)
Yet another solution:
a = {"A":3, "B":2, "C":6}
b = {"B":7, "C":4, "D":1}
Two liner:
b.update({k:max(a[k],b[k]) for k in a if b.get(k,'')})
res = {**a, **b}
Or if you don't want to change b:
b_copy = dict(b)
b_copy.update({k:max(a[k],b[k]) for k in a if b.get(k,'')})
res = {**a, **b_copy}
> {'A': 3, 'B': 7, 'C': 6, 'D': 1}

keep highest value of duplicate keys in dicts

For school i am writing a small program for a rankinglist for a game.
I am using dicts for this, with the name of the player as keyname, and the score as keyvalue.
there will be 10 games, and each game will have an automatic ranking system which i print to file.
ive already managed to code the ranking system, but now im facing a bigger challange which i cannot solve:
I have to make an overall ranking, which means someplayername can be in several contests with several scores, but i need to only keep the highest score of a duplicate.
In short: I need some help with keeping the duplicate key with the highest value:
like this:
dict1 = {"a": 6, "b": 4, "c": 2, "g": 1}
dict2 = {"a": 3, "f": 4, "g": 5, "d": 2}
dictcombined = {'a': 6, 'b': 4, 'c': 2, 'g': 5, 'f': 4, 'd': 2}
the normal merge option just takes the second dict and thus that value.
thnx in advance
You need to have a function that will keep track of the highest scores for each player. It will add a player to the total if not already there, otherwise adding it if it's higher.
Something like this:
def addScores(scores, total):
for player in scores:
if player not in total or total[player] < scores[player]:
total[player] = scores[player]
This works like a charm:
dict1 = {"a": 6, "z": 4, "g": 1, "hh": 50, "ggg": 1}
dict2 = {"a": 3, "g": 5, "d": 2, "hh": 50}
for key in dict1:
if key not in dict2 or dict1[key] > dict2[key]:
dict2[key] = dict1[key]
print (dict1)
print (dict2)
dict3 = {**dict1, **dict2}
print (dict3)
Now I can compare dict3 with other dicts and so on.
Here's a variation on Matt Eding's answer that compares each value individually instead of creating sets of values. As a plus, it doesn't need any imports.
def combine_dicts(chooser, *dicts):
combined = {}
for d in dicts:
for k, v in d.items():
if k not in combined:
combined[k] = v
else:
combined[k] = chooser(v, combined[k])
return combined
Usage:
>>> combine_dicts(max, dict1, dict2)
{'a': 6, 'b': 4, 'c': 2, 'g': 5, 'f': 4, 'd': 2}
Here is my generalized solution to your question. It's a function that can combine an arbitrary number of dictionaries and has an option for other comparison functions should you want to say, keep track of the minimum values instead.
import collections
def combine_dicts(func, *dicts):
default = collections.defaultdict(set)
for d in dicts:
for k, v in d.items():
default[k].add(v)
return {k: func(v) for k, v in default.items()}
It uses a defaultdict with set as its default_factory to keep track of repetitions of keys with different values. Then it returns a dictionary comprehension to filter out the desired values.
dict1 = {"a": 6, "b": 4, "c": 2, "g": 1}
dict2 = {"a": 3, "d": 2, "f": 4, "g": 5}
dict_comb = combine_dicts(max, dict1, dict2)
print(dict_comb) # -> {'a': 6, 'b': 4, 'c': 2, 'd': 2, 'f': 4, 'g': 5}
Yet another approach, surprisingly not proposed (since 100% built-in)
>>> dict(sorted([*dict1.items(), *dict2.items()]))
{'a': 6, 'b': 4, 'c': 2, 'd': 2, 'f': 4, 'g': 5}
If your key-value pairs are less "lexicographic", you may want to target the numerics specifically, doing
>>> dict(sorted([*dict1.items(), *dict2.items()], key=lambda item: item[1]))
{'g': 5, 'c': 2, 'd': 2, 'a': 6, 'b': 4, 'f': 4}
You might consider using Pandas for this. It also has a ton of other helpful functionality for working with data.
There's probably an ideal way to solve this, but the first thing I thought of is to create two Series (which are sort of like dicts), concatenate them, group by the labels (a, b, c, etc.), then get the max for each group.
import pandas as pd
s1, s2 = [pd.Series(d, name='Scores') for d in [dict1, dict2]]
result = pd.concat([s1, s2]).groupby(level=0).max()
>>> result
a 6
b 4
c 2
d 2
f 4
g 5
Name: Scores, dtype: int64
If you want the result as a dict:
>>> result.to_dict()
{'a': 6, 'b': 4, 'c': 2, 'd': 2, 'f': 4, 'g': 5}

Removing duplicate keys from python dictionary but summing the values

I have a dictionary in python
d = {tags[0]: value, tags[1]: value, tags[2]: value, tags[3]: value, tags[4]: value}
imagine that this dict is 10 times bigger, it has 50 keys and 50 values. Duplicates can be found in this tags but even then values are essential. How can I simply trimm it to recive new dict without duplicates of keys but with summ of values instead?
d = {'cat': 5, 'dog': 9, 'cat': 4, 'parrot': 6, 'cat': 6}
result
d = {'cat': 15, 'dog': 9, 'parrot': 6}
I'd like to improve Paul Seeb's answer:
tps = [('cat',5),('dog',9),('cat',4),('parrot',6),('cat',6)]
result = {}
for k, v in tps:
result[k] = result.get(k, 0) + v
tps = [('cat',5),('dog',9),('cat',4),('parrot',6),('cat',6)]
from collections import defaultdict
dicto = defaultdict(int)
for k,v in tps:
dicto[k] += v
Result:
>>> dicto
defaultdict(<type 'int'>, {'dog': 9, 'parrot': 6, 'cat': 15})
Instead of just doing dict of those things (can't have multiples of same key in a dict) I assume you can have them in a list of tuple pairs. Then it is just as easy as
tps = [('cat',5),('dog',9),('cat',4),('parrot',6),('cat',6)]
result = {}
for k,v in tps:
try:
result[k] += v
except KeyError:
result[k] = v
>>> result
{'dog': 9, 'parrot': 6, 'cat': 15}
changed mine to more explicit try-except handling. Alfe's is very concise though
This the perfect situation for using a Counter data structure.
Let's take a look at what it does on few familiar data structures:
>>> from collections import Counter
>>> list_a = ["A", "A", "B", "C", "C", "A", "D"]
>>> list_b = ["B", "A", "B", "C", "C", "C", "D"]
>>> c1 = Counter(list_a)
>>> c2 = Counter(list_b)
>>> c1
Counter({'A': 3, 'C': 2, 'B': 1, 'D': 1})
>>> c2
Counter({'C': 3, 'B': 2, 'A': 1, 'D': 1})
>>> c1 - c2
Counter({'A': 2})
>>> c1 + c2
Counter({'C': 5, 'A': 4, 'B': 3, 'D': 2})
>>> c_diff = c1 - c2
>>> c_diff.update([77, 77, -99, 0, 0, 0])
>>> c_diff
Counter({0: 3, 'A': 2, 77: 2, -99: 1})
As you can see this behaves as a set that keeps the count of element occurrences as a value.
However, the dictionary in itself is a set-like structure where for values we don't have to have numbers, so the things get more interesting:
>>> dic1 = {"A":"a", "B":"b"}
>>> cd = Counter(dic1)
>>> cd
Counter({'B': 'b', 'A': 'a'})
>>> cd.update(B='bB123')
>>> cd
Counter({'B': 'bbB123', 'A': 'a'})
>>> dic2 = {"A":[1,2], "B": ("a", 5)}
>>> cd2 = Counter(dic2)
>>> cd2
Counter({'B': ('a', 5), 'A': [1, 2]})
>>> cd2.update(A=[42], B=(2,2))
>>> cd2
Counter({'B': ('a', 5, 2, 2), 'A': [1, 2, 42, 42, 42, 42]})
>>> cd2 = Counter(dic2)
>>> cd2
Counter({'B': ('a', 5), 'A': [1, 2]})
>>> cd2.update(A=[42], B=("new elem",))
>>> cd2
Counter({'B': ('a', 5, 'new elem'), 'A': [1, 2, 42]})
As we can see the value we are adding/changing has to be of the same type in update or it throws TypeError.
For the situation we have in the question, we can just go with the flow
>>> d = {'cat': 5, 'dog': 9, 'cat': 4, 'parrot': 6, 'cat': 6}
>>> cd3 = Counter(d)
>>> cd3
Counter({'dog': 9, 'parrot': 6, 'cat': 6})
>>> cd3.update(parrot=123)
>>> cd3
Counter({'parrot': 129, 'dog': 9, 'cat': 6})
Perhapse what you really want is a tuple of key-value pairs.
[('dog',1), ('cat',2), ('cat',3)]
I'm not sure what you're trying to achieve, but the Counter class might be helpful for what you're trying to do:
http://docs.python.org/dev/library/collections.html#collections.Counter
This option serves but is done with a list, or best can provide insight
data = []
for i, j in query.iteritems():
data.append(int(j))
try:
data.sort()
except TypeError:
del data
data_array = []
for x in data:
if x not in data_array:
data_array.append(x)
return data_array
If I understand correctly your question that you want to get rid of duplicate key data, use update function of dictionary while creating the dictionary. it will overwrite the data if the key is duplicate.
tps = [('cat',5),('dog',9),('cat',4),('parrot',6),('cat',6)]
result = {}
for k, v in tps:
result.update({k:v})
for k in result:
print "%s: %s" % (k, result[k])
Output will look like:
dog: 9
parrot: 6
cat: 6

Categories

Resources