What is the best way to create a dict from two other dicts (very big one and small one)?
We have:
big_dict = {
'key1':325,
'key2':326,
'key3':327,
...
}
small_dict = {
325:0.698,
326:0.684,
327:0.668
}
Needs to get a dict for data in small_dict, but we should use keys from big_dict:
comb_dict = {
'key1':0.698,
'key2':0.684,
'key3':0.668
}
The following code works with all cases (example shown in the driver values), with a more EAFP oriented approach.
>>> d = {}
>>> for key,val in big_dict.items():
try:
d[key] = small_dict[val]
except KeyError:
continue
=> {'key1': 0.698, 'key2': 0.684, 'key3': 0.668}
#driver values :
IN : big_dict = {
'key1':325,
'key2':326,
'key3':327,
'key4':330 #note that small_dict[330] will give KeyError
}
IN : small_dict = {
325:0.698,
326:0.684,
327:0.668
}
Or, using Dictionary Comprehension :
>>> {key:small_dict[val] for key,val in big_dict.items() if val in small_dict}
=> {'key1': 0.698, 'key2': 0.684, 'key3': 0.668}
If there are values in big_dict that may not be present as keys in small_dict, this will work:
combined_dict = {}
for big_key, small_key in big_dict.items():
combined_dict[big_key] = small_dict.get(small_key)
Or you might want to use a different default value instead with:
combined_dict[big_key] = small_dict.get(small_key, default='XXX')
Or you might want to raise a KeyError to indicate a problem with your data:
combined_dict[big_key] = small_dict[small_key]
Or you might want to skip missing keys:
if small_key in small_dict:
combined_dict[big_key] = small_dict[small_key]
You could use dictionary comprehension:
comb_dict = {k: small_dict[v] for k, v in big_dict.iteritems()}
If big_dict may contain values that are not keys in small_dict you could just ignore them:
comb_dict = {k: small_dict[v] for k, v in big_dict.iteritems() if v in small_dict}
or use the original value:
{k: (small_dict[v] if v in small_dict else v) for k, v in big_dict.iteritems()}
(Use items() in Python3)
keys = small_dict.keys()
combined_dict = {k:small_dict[v] for k,v in big_dict.items() if v in keys}
>>> combined_dict
{'key3': 0.668, 'key2': 0.684, 'key1': 0.698}
Related
I have this data:
data =
{
"a":{
"00066554466":{
"Id":650,
"Passwd":"e1c2a06545de9164d7e87cd98bed57c5",
"zone":"Europe/Zurich"
},
"8745212300":{
"Id":400,
"Passwd":"ecb95502daace7f46bf12b484d086e5b",
"zone":"Europe/Zurich"
},
"8745212301":{
"Id":401,
"Passwd":"ecb95502daace7f46bf12b484d086e5b",
"zone":"Europe/Zurich"
},
"8745212302":{
"DevId":402,
"Passwd":"ecb95502daace7f46bf12b484d086e5b",
"zone":"Europe/Zurich"
}
}
}
I would like to group keys with same Passwd. So result should be like the following.
{
"e1c2a06545de9164d7e87cd98bed57c5":[
"00066554466"
],
"ecb95502daace7f46bf12b484d086e5b":[
"8745212300",
"8745212301",
"8745212302"
]
}
I tried with itertools.groupby and with for k,v in xxx, but the result is never what I need.
itertools.groupby works well when then data is already sorted with values to be grouped in a successive order, which might not always be the case with your data.
Rather use dict.setdefault and a nested loop:
out = {}
for d1 in data.values():
for k, d2 in d1.items():
out.setdefault(d2['Passwd'], []).append(k)
print(out)
Variant with a defaultdict:
from collections import defaultdict
out = defaultdict(list)
for d1 in data.values():
for k, d2 in d1.items():
out[d2['Passwd']].append(k)
print(dict(out))
Output:
{'e1c2a06545de9164d7e87cd98bed57c5': ['00066554466'],
'ecb95502daace7f46bf12b484d086e5b': ['8745212300', '8745212301', '8745212302']}
One solution, but probably not the pythonic is just to do:
passwd_group = {}
for k, val in data["a"]:
if val["Passwd"] not in passwd_group:
passwd_group[val["Passwd"]] = []
passwd_group.append(k)
This may not be ideal but got it working.
new_dict = {}
for L in data.keys():
x = data[L]
for M in x.keys():
y = x[M]
for N in y.keys():
if N == "Passwd":
new_list = new_dict.get(y[N], [])
new_list.append(M)
new_dict[y[N]] = new_list
print(new_dict)
I have a dictionary of key-value pairs, where the value is itself a dictionary. I would like to change the names of key values in that nested dictionary based on a predefined conversion.
I am using two lists to match up the values of the nested keys that I am trying to conver (Old_item1 should become New_item1):
comparison_list = ['Old_item1', 'Old_item2']
new_prods = ['New_item1', 'New_item2']
old_dict = {
'Company1':
{
'Old_item1':
{
'key1': val,
'key2': val
},
'Old_item2':
{
'key1': val,
'key2': val
}
}
}
I tried this:
new_dict = {}
for i in comparison_list:
for j in new_prods:
new_dict['Company1'][j] = test['Company1'][i]
I get a KeyError: KeyError: 'Company1'
The desired output for each item I add to each list is:
new_dict = {
'Company1':
{
'New_item1':
{
'key1': val # old item key, val
'key2': val # old item key, val
}
}
}
You can make a dictionary of mappings from the old to the new items, and then use it to create a new sub-dictionary for each company. This then needs to be wrapped inside an outer loop over companies (although here there is only one).
For example:
comparison_list = ['Old_item1', 'Old_item2']
new_prods = ['New_item1', 'New_item2']
old_dict = {'Company1':
{'Old_item1':
{'key1': 2,
'key2': 3},
'Old_item2':
{'key1': 4,
'key2': 5}}}
key_mappings = dict(zip(comparison_list, new_prods))
new_dict = {k: {key_mappings[k1]: v1 for k1, v1 in v.items()}
for k, v in old_dict.items()}
print(new_dict)
gives:
{'Company1': {'New_item1': {'key1': 2, 'key2': 3}, 'New_item2': {'key1': 4, 'key2': 5}}}
Here is the mappings dictionary key_mappings which we used:
{'Old_item1': 'New_item1', 'Old_item2': 'New_item2'}
The easiest way to go about this is to re-create your dictionary with a comprehension:
new_dict = {company: update_item(v) for company, v in old_dict.items()}
Then parse out update_item to it's own function. You could do this inline but it makes it difficult to understand.
conversion_lookup = {
'Old_item1': 'NewItem1',
'Old_item2': 'NewItem2',
}
def update_item(item: dict) -> dict:
return { conversion_lookup.get(k, k): v for k, v in item.items() }
new_dict = {company: update_item(v) for company, v in old_dict.items()}
For the conversion here I'm using a dictionary describing the conversion. If you need to construct this automatedly:
comparison_list = ['Old_item1', 'Old_item2']
new_prods = ['New_item1', 'New_item2']
conversion_lookup = { v: new_prods[idx] for idx, v in enumerate(comparison_list) }
The reason I like a dictionary is that you can use some_dict.get(a_value, a_default_value). Then, if your value isn't in your conversion dictionary you can fall back to the original value. That's what I'm doing here:
conversion_lookup.get(k, k)
The second k is the original item's value, which is a good thing to use if your conversion list doesn't include what you want.
One approach is to do it step by step. First create the dicts with the new names and old keys, then remove the old keys, and finally add in the new names.
# Keep the values from the old keys
values = [old_dict['Company1'][old_name] for old_name in comparison_list]
# Remove old names, and add in the
for new_key, value, old in zip(new_prods, values, comparison_list):
old_dict['Company1'].pop(old)
old_dict['Company1'][new_key] = value
This question already has answers here:
Access nested dictionary items via a list of keys?
(20 answers)
Closed 4 years ago.
Let's say i have a list of keys
key_lst = ["key1", "key2", "key3"]
and i have a value
value = "my_value"
and an example dict my_dict with this structure
{
"key1": {
"key2": {
"key3": "some_value"
}
},
}
How can I dynamically assign the new value in variable value to my_dict["key1"]["key2"]["key3"] by going thru / looping over my key_lst?
I can not just say my_dict["key1"]["key2"]["key3"] = value since the keys and the number of keys is changing. I always get the keys (the path that i have to save the value at) in a list...
The output I am looking for is {'key1': {'key2': {'key3': 'my_value'}}}. The dictionary structure is predefined.
I'm using Python 3.7
Predefined dictionary structure: functools.reduce
You can define a function using functools.reduce to apply getitem repeatedly and then set a supplied value:
from functools import reduce
from operator import getitem
def set_nested_item(dataDict, mapList, val):
"""Set item in nested dictionary"""
reduce(getitem, mapList[:-1], dataDict)[mapList[-1]] = val
return dataDict
key_lst = ["key1", "key2", "key3"]
value = "my_value"
d = {"key1": {"key2": {"key3": "some_value"}}}
d = set_nested_item(d, key_lst, value)
print(d)
# {'key1': {'key2': {'key3': 'my_value'}}}
Note operator.getitem is used to access dict.__getitem__, or its more commonly used syntactic sugar dict[]. In this instance, functools.reduce calls getitem recursively on dataDict, successively using each value in mapList[:-1] as an argument. With [:-1], we intentionally leave out the last value, so we can use __setitem__ via dict[key] = value for the final key.
Arbitrary dictionary nesting: collections.defaultdict
If you wish to add items at arbitrary branches not yet been defined, you can construct a defaultdict. For this, you can first defaultify your regular dictionary input, then use set_nested_item as before:
from collections import defaultdict
def dd_rec():
return defaultdict(dd_rec)
def defaultify(d):
if not isinstance(d, dict):
return d
return defaultdict(dd_rec, {k: defaultify(v) for k, v in d.items()})
dd = defaultify(d)
key_lst = ["key1", "key2", "key5", "key6"]
value = "my_value2"
dd = set_nested_item(dd, key_lst, value)
print(dd)
# defaultdict(<function __main__.<lambda>>,
# {'key1': defaultdict(<function __main__.<lambda>>,
# {'key2': defaultdict(<function __main__.<lambda>>,
# {'key3': 'my_value',
# 'key5': defaultdict(<function __main__.<lambda>>,
# {'key6': 'my_value2'})})})})
You can iteratively build/access levels using setdefault in a loop:
d = {}
d2 = d
for k in key_lst[:-1]:
d2 = d2.setdefault(k, {})
d2[key_lst[-1]] = value
print(d)
# {'key1': {'key2': {'key3': 'my_value'}}}
d is the reference to your dictionary, and d2 is a throw-away reference that accesses inner levels at each iteration.
This is what you want:
def update(d, key_lst , val):
for k in key_lst[:-1]:
if k not in d:
d[k] = {}
d = d[k]
d[key_lst[-1]] = val
d = {}
update(d, list('qwer'), 0)
# d = {'q': {'w': {'e': {'r': 0}}}}
You could use defaultdict too, it's neat in a sense but prints rather ugly...:
from collections import defaultdict
nest = lambda: defaultdict(nest)
d = nest()
def update(d, key_lst , val):
for k in key_lst[:-1]:
d = d[k]
d[key_lst[-1]] = val
update(d, 'qwer', 0)
I guess you can loop through your keys like this :
d = {}
a = d
for i in key_lst:
a[i] = {}
if i == key_lst[-1]:
a[i] = value
else:
a = a[i]
print(d)
# {'key1': {'key2': {'key3': 'my_value'}}}
Edit: I guess I misread the question and answered as if the dictionnary wasn't already existing. jpp answer is pretty neat otherwise I guess!
key_lst = ["key1", "key2", "key3"]
my_dict={
"key1": {
"key2": {
"key3": "some_value"
}
},
}
val=my_dict
#loop gets second to last key in chain(path) and assigns it to val
for x in key_lst[:-1]:
val=val[x]
#now we can update value of last key, cause dictionary key is passed by reference
val[key_lst[-1]]="new value"
print (my_dict)
#{'key1': {'key2': {'key3': 'new value'}}}
I need to do a not "natural" operation on a dictionary so i wondering what is the best pythonic way to do this.
I need to simplify a dictionary by removing all the keys on it with the same value (keys are differents, values are the same)
For example:
Input:
dict = {key1 : [1,2,3], key2: [1,2,6], key3: [1,2,3]}
expected output:
{key1 : [1,2,3], key2:[1,2,6]}
I dont care about which key is delete (on the example: key1 or key3)
Exchange keys and values; duplicated key-value pairs will be removed as a side effect (because dictionary does not allow duplicated keys). Exchange keys and values again.
>>> d = {'key1': [1,2,3], 'key2': [1,2,6], 'key3': [1,2,3]}
>>> d2 = {tuple(v): k for k, v in d.items()} # exchange keys, values
>>> d = {v: list(k) for k, v in d2.items()} # exchange again
>>> d
{'key2': [1, 2, 6], 'key1': [1, 2, 3]}
NOTE: tuple(v) was used because list is not hashable; cannot be used as key directly.
BTW, don't use dict as a variable name. It will shadow builtin function/type dict.
This solution deletes the keys with same values without creating a new dictionary.
seen = set()
for key in mydict.keys():
value = tuple(mydict[key])
if value in seen:
del mydict[key]
else:
seen.add(value)
I think you can do it this way also. But I don't say as there seems to be more efficient ways. It is in-line.
for i in dictionary.keys():
if dictionary.values().count(dictionary[i]) > 1:
del dictionary[i]
You can iterate over your dict items and use a set to check what we have seen so far, deleting a key if we have already seen the value:
d = {"key1" : [1,2,3], "key2": [1,2,6], "key3": [1,2,3]}
seen = set()
for k, v in d.items(): # list(items) for python3
temp = tuple(v)
if temp in seen:
del d[k]
seen.add(temp)
print(d)
{'key1': [1, 2, 3], 'key2': [1, 2, 6]}
This will be more efficient that using creating a dict and reversing the values as you only have to cast to tuple once not from a tuple back to a list.
this worked for me:
seen = set()
for key in mydict.copy():
value = tuple(mydict[key])
if value in seen:
del mydict[key]
else:
seen.add(value)
I'm new to Python and stuck at something basic.
Say there's a list of dictionaries as follows:
[{key1:value1},{key2:value2},...{keyn:valuen}]
is there a pythonic way of extracting the dictionary
{key1:value1},{key2:value2},...{keyn:valuen}
I'm assuming you mean that you want {key1: value1, key2:value2, keyn:valuen}. That is, you want to combine all the separate dictionaries into a single one with each of the keys and values from the individual dictionaries.
Here's how I'd do it, using a dictionary comprehension:
l = [{"key1":"value1"},{"key2":"value2"},{"keyn":"valuen"}]
result = {k:v for d in l for k, v in d.iteritems()}
print result # {'key2': 'value2', 'key1': 'value1', 'keyn': 'valuen'}
Same thing, in perhaps an easier way to read:
result = {}
d_list = [{"key1": "value1"}, {"key2": "value2"}, {"keyn": "valuen"}]
for d in d_list:
for k, v in d.iteritems():
result[k] = v
a=[{1:1},{2:2},{3:3}]
result=dict([(k,v) for x in a for k,v in x.items()])
print result //{1: 1, 2: 2, 3: 3}