Add dictionary key-values to all keys of another dictionary - python

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]

Related

How do I rename a key while preserving order in dictionaries (Python 3.7+)?

I have a dictionary, with this value:
{"a": 1, "b": 2, "c": 3}
I would like to rename the key b to B, without it losing its second place. In Python 3.7 and higher, dictionaries preserve insertion order, so the order of the keys can be counted on and might mean something. The end result I'm looking for is:
{"a": 1, "B": 2, "c": 3}
The obvious code would be to run:
>>> dictionary["B"] = dictionary.pop("b")
{'a': 1, 'c': 3, 'B': 2}
However, this doesn't preserve the order as desired.
foo = {'c': 2, 'b': 4, 'J': 7}
foo = {key if key != 'b' else 'B': value for key, value in foo.items()}
foo
Out[7]: {'c': 2, 'B': 4, 'J': 7}
This solution modifies the dictionary d in-place. If performance is not a concern, you could do the following:
d = {"a": 1, "b": 2, "c": 3, "d": 4}
replacement = {"b": "B"}
for k, v in list(d.items()):
d[replacement.get(k, k)] = d.pop(k)
print(d)
Output:
{'a': 1, 'B': 2, 'c': 3, 'd': 4}
Notice that the above solution will work for any numbers of keys to be replaced. Also note that you need to iterate over a copy of d.items() (using list(d.items())), as you shouldn't iterate over a dictionary while modifying its keys.
As a variant of the existing answers that also works for more than once replacement, you can define another dictionary showing which keys to replace with that other keys:
>>> d = {"a": 1, "b": 2, "c": 3}
>>> repl = {"b": "B"}
>>> {repl.get(k, k): d[k] for k in d}
{'a': 1, 'B': 2, 'c': 3}
Of course, this still creates a new dictionary instead of updating the existing one and thus needs O(n), but at least it does so just once for all keys that need to be updated.
dict1 = {"a": 1, "b": 2, "c": 3}
dict2 = dict()
for key in dict1:
if key == 'b':
dict2[key.upper()] = dict1[key]
else:
dict2[key] = dict1[key]
dict1 = dict2 #if you want to have it in original dict
You can set whatever value you want in if statement

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}

How does python achieve the following data format conversion?

I would like to achieve a function that deals with the following dataļ¼š'd' and generate 'L'. How to achieve?
def func(**d):
'do something'
return [....]
source:
d = {'a': 1, 'b': 2, 'c': [3, 4, 5]}
or
d = {'a': 1, 'b': 2, 'c': [3, 4, 5], 'd': [6, 7]}
TO:
L=[{'a':1,'b':2,'c':3},
{'a':1,'b':2,'c':4},
{'a':1,'b':2,'c':5}]
or
L=[{'a': 1, 'b': 2, 'c': 3, 'd': 6},
{'a': 1, 'b': 2, 'c': 3, 'd': 7},
{'a': 1, 'b': 2, 'c': 4, 'd': 6},
{'a': 1, 'b': 2, 'c': 4, 'd': 7},
{'a': 1, 'b': 2, 'c': 5, 'd': 6},
{'a': 1, 'b': 2, 'c': 5, 'd': 7}]
d = {'a': 1, 'b': 2,' c': [3, 4, 5]}
temp_d = d
L = []
for key in temp_d:
item = {}
for key in temp_d:
if isinstance(temp_d[key], list):
item[key] = temp_d[key].pop(0)
else:
item[key] = temp_d[key]
L.append(item)
Basically, what i am doing here is:
I create a copy of the dictionary 'd' named 'temp_d';
I go through every key in the 'temp_d ' dictionary, and create an empty one;
I loop again through all the keys in the 'd' dictionary, and basically I verify if the value of the current key of the loop is a list, if it is, I add the key to the dictionary 'item' with the first value of the list, with the function pop(index) (this function removes an element from a list and returns it). If the value of the current key isn't a list, it just adds the key to the dict with the value.
After filling the dictionary 'item', I append it to 'L'.
Example in this case:
first key ('a'):
item = {}
first key of second loop ('a'):
is the value of 'a' a list?
no. adds the value.
new item{'a': 1}
second key of second loop ('b'):
is the value of 'b' a list?
no. adds the value.
new item{'a': 1, 'b': 2}
third key of second loop ('c'):
is the value of 'c' a list?
yes. adds the first element of the list, removing it from the list
(the list was [3, 4, 5], now is [4, 5])
new item{'a': 1, 'b': 2, 'c': 3}
appends the item to L
(the 'L' was [], now is [{'a': 1, 'b': 2, 'c': 3}])
etc until the end.
This will work with python 3:
d = {'a': 1, 'b': 2, 'c': [3, 4, 5]}
def f(**d):
return [{**d, 'c': i} for i in d.pop('c')]
Your problem can be solved as follows:
from itertools import cycle
def func(indict):
dictlist = [dict(indict)] # make copy to not change original dict
for key in indict: # loop keys to find lists
if type(indict[key]) == list:
listlength = len(indict[key])
dictlist = listlength * dictlist # elements are not unique
for dictindex, listelement in zip(range(len(dictlist)), cycle(indict[key])):
dictlist[dictindex] = dict(dictlist[dictindex]) # uniquify
dictlist[dictindex][key] = listelement # replace list by list element
return dictlist
In the general case you can have multiple lists in your dict. My solution assumes you want to unroll all of these.
Looking at the details of the solution, it starts by adding a copy of your original dict to dictlist then it cycles the elements and whenever it finds a list, it multiplies the dictlist with the the length of the list found. This will ensure that dictlist contains the correct number of elements.
However, the elements will not be unique as they will be references to the same underlying dicts.
To fix this, the elements of the dict list are "uniquified" by looping the list and replacing every element with a copy of itself and the list in the original indict is replaced by each element of the list, cycling the different elements of dictlist.
I know my explanation is a bit messy. I'm sorry about that, but I find it hard to explain in a short and simple way.
Also, the order of the element in the list, is not identical to what you ask for in the question. Since the individual key-value pairs of the dict are not ordered, it is not possible to ensure which order the elements will be unrolled, which leads to the list order is also not ensured.

How can I get the values that are common to two dictionaries, even if the keys are different?

Starting from two different dictionaries:
dict_a = {'a': 1, 'b': 3, 'c': 4, 'd': 4, 'e': 6}
dict_b = {'d': 1, 'e': 6, 'a': 3, 'v': 7}
How can I get the common values even if they have different keys? Considering the above dictionaries, I would like to have this output:
common = [1, 3, 6]
Create sets from the values:
list(set(dict_a.values()) & set(dict_b.values()))
This creates an intersection of the unique values in either dictionary:
>>> dict_a = {'a': 1, 'b': 3, 'c': 4, 'd': 4, 'e': 6}
>>> dict_b = {'d': 1, 'e': 6, 'a': 3, 'v': 7}
>>> list(set(dict_a.values()) & set(dict_b.values()))
[1, 3, 6]
Unfortunately, we can't use dictionary views here (which can act like sets), because dictionary values are not required to be unique. Had you asked for just the keys, or the key-value pairs, the set() calls would not have been necessary.
Try this,
commom = [item for item in dict_b.values() if item in dict_a.values()]
The intersection expression & requires 2 sets but the method counterpart can work with any iterable, like dict.values. So here is another version of the Martijn Pieters solution :
list(set(dict_a.values()).intersection(dict_b.values()))
My 2 cents :)

Combining dictionaries within dictionaries & adding values

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

Categories

Resources