Using dict keys in python as values in a different dict - python

I would like to create a "translator" type of dict that would assign values that are keys in different dicts, which are nested, to keys in a dict that I created. The problem I run into is that I can't create a value that represents a nested dict key without having to convert that to a string or some other data type, and when I try to use a string as an index to the nested dict, I get an index error. Ideally, my dict would look something like this:
new_dict{
"new_key_1" : ['subdict1']['subdict2']['old_key_1'],
"new_key_2" : ['subdict1']['subdict2']['old_key_2'],
"new_key_3" : ['subdict1']['subdict3']['old_key_3']
}
Then, for each nested dict, I could generate a new dict object with a simple for loop:
for key, value in new_dict.items() :
user_dict_1[key] = OldDict[value]
The nested dicts are very large and I only need a few fields from each, otherwise I could just use the .copy() function to work with the old dicts.
PS- Any help in rewriting this question to be more readable also appreciated.

You're going to need reduce() for this one...
attrmap = {
"new_key_1": ('subdict1', 'subdict2', 'old_key_1'),
...
}
print reduce(lambda x, y: x[y], attrmap[somekey], old_object)

Are you talking something like this?
from pprint import pprint as pp
subdict1 = {'subdict1_item1':1, 'subdict1_item2':2}
subdict2 = {'subdict2_item1':3, 'subdict2_item2':4}
subdict3 = {'subdict3_item1': 5, 'subdict3_item1':6}
olddict = {
'old_key_1': [subdict1, subdict2],
'old_key_2': [subdict1, subdict2],
'old_key_3': [subdict1, subdict3],
}
newdict = {
'new_key_1': olddict['old_key_1'].append('old_key_1'),
'new_key_2': olddict['old_key_2'].append('old_key_2'),
'new_key_3': olddict['old_key_3'].append('old_key_3'),
}
or this
newdict = {
'new_key_1': 'old_key_1',
'new_key_2': 'old_key_2',
'new_key_3': 'old_key_3',
}
def getnew(newkey, newdict, olddict):
if newkey in newdict:
oldkey = newdict[newkey]
if oldkey in olddict:
preitem = olddict[ oldkey ] # returns a list with two items
item = []
item.append([preitem[0]]) # makes subdict1 wrapped in a list
item.append([preitem[1]]) # makes subdict2/3 wrapped in a list
item.append([oldkey])
return item
else:
raise KeyError('newdict has no matching olddict key')
results to:
pp( getnew('new_key_1', newdict, olddict) )
print
pp( getnew('new_key_2', newdict, olddict) )
print
pp( getnew('new_key_3', newdict, olddict) )
[[{'subdict1_item1': 1, 'subdict1_item2': 2}],
[{'subdict2_item1': 3, 'subdict2_item2': 4}],
['old_key_1']]
[[{'subdict1_item1': 1, 'subdict1_item2': 2}],
[{'subdict2_item1': 3, 'subdict2_item2': 4}],
['old_key_2']]
[[{'subdict1_item1': 1, 'subdict1_item2': 2}],
[{'subdict3_item1': 6}],
['old_key_3']]

Related

List all keys in dictionaries which are inside a list. (Dictionary in a list)

Okay, not sure how to explain this problem but here goes.
This is my dictionary myDictionary = {'12/2019' : [{'1003' : 2}, {'1040' : 3}]}
I'm trying to list out the '1003', '1040'.
I've tried using this method:
for i in range(len(a['12/2019'])):
print(a['12/2019'][i].keys())
It kind of works however it returns me
dict_keys(['1003'])
dict_keys(['1040'])
Is there anyway I can just get 1030 and 1040 to be isolated from the ... dict_keys([''])?
You can iterate over the values of the dictionary, and if the value is a list, iterate over the dictionaries in the list, and append all the keys to the result
myDictionary = {'12/2019' : [{'1003' : 2}, {'1040' : 3}],
'11/2019': '1005', '10/2019': 1234,
'09/2019': [{'1006' : 2}, {'1042' : 3}],
'08/2019': (1,2)}
keys=[]
#Iterate over values
for value in myDictionary.values():
#If value is a list
if isinstance(value, list):
#Iterate over the list
for d in value:
#Add the keys to the result
keys.extend(list(d.keys()))
print(keys)
The output will be
['1003', '1040', '1006', '1042']
You can also do this via a list-comprehension, but it's not really readable, so I would avoid against it
[key for value in myDictionary.values() if isinstance(value, list) for d in value for key in d.keys()]
Iterate over the sub-dicts in the list, grabbing the keys:
for sub_dict in a['12/2019']:
for key, val in sub_dict.items():
print(key)
You can use a list-comprehension:
[k for v in myDictionary.values() for x in v for k in x]
In code:
myDictionary = {'12/2019' : [{'1003' : 2}, {'1040' : 3}]}
print([k for v in myDictionary.values() for x in v for k in x])
# ['1003', '1040']
You could do this by doing something like this
data = {'12/2019' : [{'1003' : 2}, {'1040' : 3}]}
# Data is a dictionary of where each value corresponding
# to the key is a list of dictionaries.
for k, v in data.items():
# v is a list of dictionaries
all_keys = []
for value in v:
all_keys.extend(list(value.keys()))
print (all_keys)
The result is ['1003', '1040']
This may be more than you need, but if the data you shared for the example is just a small subset of what you're really looking at, here's a recursive function that can go as deep as you want it to.
Since you seem to want to skip the keys in the outer most level, I put in a spot to allow you to skip over the keys at a given depth. You shouldn't set the level argument manually since the code will just update that for itself.
def list_keys(element, ignore_levels=[], level=1):
"""
Recursivly list keys found in an element.
element: item to inspect.
ignore_levels: list of numeric levels to ignore.
level: recursion depth level.
"""
keys = []
# add keys if we're not ignoring this level and set iterable to values
if isinstance(element, dict):
if level not in ignore_levels:
keys.extend(element.keys())
iterable = element.values()
# if we hve a list or tuple, we can iterate over it
elif isinstance(element, (list, tuple)):
iterable = element
# if we have a single value, it's not a key and there's nothing to iterate
else:
iterable = []
# Iterate over elements and append any keys found
for i in iterable:
subkeys = list_keys(i, ignore_levels, level + 1)
if subkeys:
keys.extend(subkeys)
return keys
d = {'12/2019': [{'1003': 2}, {'1040': 3}]}
print(list_keys(d, ignore_levels=[1]))
# ['1003', '1040']

python dicts of dicts out of python dicts

I have predefined dictionaries and I need a function to form one dictionary out of several input dicts where the keys are the names of the input dictionaries.
For example, I have the following:
double_left = {
'left': 6
}
double_right = {
'right': 6
}
The output should be:
>>> output_dicts
{'double_left': {'left': 6}, 'double_right': {'right': 6}}
I already tried:
How do you create nested dict in Python?
but could not derive the answer.
Suggestions ?
If you want to do it dynamically without hardcoding the names of the top-level items, you can get a list of variables by names using globals() and/or locals(). For example:
output = {}
for name, val in globals().items():
# Skipping variables that aren't dicts, and special
# variables starting with '_'
if isinstance(val, dict) and not name.startswith('_'):
output[name] = val
for name, val in locals().items():
if isinstance(val, dict) and not name.startswith('_'):
output[name] = val
Or more compact:
output = {name:val for name, val in (list(locals().items()) +
list(globals().items()))
if isinstance(val, dict) and not name.startswith('_')}
Just make a new dictionary.
output_dict = {"double_left": double_left, "double_right": double_right}
print(output_dict)
Just like your current dicts have 'key': 'value' pairs, with your values being ints (6), you can create a new dict with the keys being the name of the dict and the values being the nested dict.
output_dicts = {'double_left': double_left, 'double_right': double_right}
>>> output_dicts
{'double_left': {'left': 6}, 'double_right': {'right': 6}}
You can also use dict_name[new_key] = new_value.
For example:
output_dicts['double_left'] = double_left
output_dicts['double_right'] = double_right
Try this
Newdict = dict(double_left = { 'left': 6},double_right =
{'right': 6})

Nested lists to nested dicts

I've a list with master keys and a list of list of lists, where the first value of each enclosed list (like 'key_01') shall be a sub key for the corresponding values (like 'val_01', 'val_02'). The data is shown here:
master_keys = ["Master_01", "Master_02", "Master_03"]
data_long = [[['key_01','val_01','val_02'],['key_02','val_03','val_04'], ['key_03','val_05','val_06']],
[['key_04','val_07','val_08'], ['key_05','val_09','val_10'], ['key_06','val_11','val_12']],
[['key_07','val_13','val_14'], ['key_08','val_15','val_16'], ['key_09','val_17','val_18']]]
I would like these lists to be combined into a dictionary of dictionaries, like this:
master_dic = {
"Master_01": {'key_01':['val_01','val_02'],'key_02': ['val_03','val_04'], 'key_03': ['val_05','val_06']},
"Master_02": {'key_04': ['val_07','val_08'], 'key_05': ['val_09','val_10'], 'key_06': ['val_11','val_12']},
"Master_03": {'key_07': ['val_13','val_14'], ['key_08': ['val_15','val_16'], 'key_09': ['val_17','val_18']}
}
What I've got so far is the sub dict:
import itertools
master_dic = {}
servant_dic = {}
keys = []
values = []
for line in data_long:
for item in line:
keys.extend(item[:1])
values.append(item[1:])
servant_dic = dict(itertools.izip(keys, values))
Which puts out a dictionary, as expected.
servant_dic = {
'key_06': ['val_11','val_12'], 'key_04': ['val_08','val_07'], 'key_05': ['val_09','val_10'],
'key_02': ['val_03','val_04'], 'key_03': ['val_05','val_06'], 'key_01': ['val_01','val_02']
}
The problem is, that if I want to add the master_keys to this dictionary, so I get the wanted result, I'd have to do this in a certain order, which would be possible, if each line had a counter like this:
enumerated_dic =
{
0: {'key_01':['val_01','val_02'],'key_02': ['val_03','val_04'], 'key_03': ['val_05','val_06']},
1: {'key_04': ['val_07','val_08'], 'key_05': ['val_09','val_10'], 'key_06': ['val_11','val_12']},
2: {'key_07': ['val_13','val_14'], ['key_08': ['val_15','val_16'], 'key_09': ['val_17','val_18']}
}
I'd love to do this with enumerate(), while each line of the servant_dic is build, but can't figure out how. Since afterwards, i could simply replace the counters 0, 1, 2 etc. with the master_keys.
Thanks for your help.
master_keys = ["Master_01", "Master_02", "Master_03"]
data_long = [[['key_01','val_01','val_02'],['key_02','val_03','val_04'], ['key_03','val_05','val_06']],
[['key_04','val_07','val_08'], ['key_05','val_09','val_10'], ['key_06','val_11','val_12']],
[['key_07','val_13','val_14'], ['key_08','val_15','val_16'], ['key_09','val_17','val_18']]]
_dict = {}
for master_key, item in zip(master_keys, data_long):
_dict[master_key] = {x[0]: x[1:] for x in item}
print _dict
Hope this will help:
{master_key: {i[0]: i[1:] for i in subkeys} for master_key, subkeys in zip(master_keys, data_long)}
My functional approach:
master_dic = dict(zip(master_keys, [{k[0]: k[1::] for k in emb_list} for emb_list in data_long]))
print(master_dic)
You can also use pop and a dict comprehension:
for key, elements in zip(master_keys, data_long):
print {key: {el.pop(0): el for el in elements}}
...:
{'Master_01': {'key_02': ['val_03', 'val_04'], 'key_03': ['val_05', 'val_06']}}
{'Master_02': {'key_06': ['val_11', 'val_12'], 'key_04': ['val_07', 'val_08'], 'key_05': ['val_09', 'val_10']}}
{'Master_03': {'key_07': ['val_13', 'val_14'], 'key_08': ['val_15', 'val_16'], 'key_09': ['val_17', 'val_18']}}

Creating dictionary using list/tuple elements as key

I need to generate a dictionary like this:
{
'newEnv': {
'newProj': {
'newComp': {
'instances': [],
'n_thing': 'newThing'
}
}
}
}
from a tuple, like this: ('newEnv','newProj','newComp','newThing') but only if that doesn't already exists. So, I tried this:
myDict = {}
(env,proj,comp,thing) = ('newEnv','newProj','newComp','newThing')
if env not in myDict:
myDict[env] = {}
if proj not in myDict[env]:
myDict[env][proj] = {}
if comp not in myDict[env][proj]:
myDict[env][proj][comp] = {'n_thing': thing, 'instances': []}
which is pretty much working but not sure how efficient is that or if I should be doing this way at all. Any suggestion(s)??
You can use a loop (with just the first 3 keys, newThing is not a key in the chain):
myDict = {}
path = ('newEnv','newProj','newComp')
current = myDict
for key in path:
current = current.setdefault(key, {})
where current ends up as the innermost dictionary, letting you set the 'n_thing' and 'instances' keys on that.
You could use reduce() to collapse that into a one-liner:
myDict = {}
path = ('newEnv','newProj','newComp')
reduce(lambda d, k: d.setdefault(k, {}), path, myDict)
The reduce call returns the innermost dictionary, so you can use that to assign your final value:
myDict = {}
path = ('newEnv','newProj','newComp')
inner = reduce(lambda d, k: d.setdefault(k, {}), path, myDict)
inner.update({'n_thing': 'newThing', 'instances': []})
you can do something similar, maybe slightly simpler, with a defaultdict of defaultdicts (see defaultdict of defaultdict, nested for some discussion)
tree = lambda: defaultdict(tree)
base = tree()
for x in mytuple[:-2]:
base = base[x]
base[x] = mytuple[-1]
which is very similar to martijn's, just using the default functionality to create the subdicts instead of doing it directly with setdefault.
this also lets you type directly
myDict[env][proj][comp].setdefault('instances', list()).append(queue)
if that's what you are really looking for. (there's no way to remove the setdefault unfortunately; after all, I don't know ahead of time whether you want a list or dict. you only have one default)....

Python: Get dictionary keys as list sorted by sub dictionary value

I have the following structure:
structure = {
'pizza': {
# other fields
'sorting': 2,
},
'burger': {
# other fields
'sorting': 3,
},
'baguette': {
# other fields
'sorting': 1,
}
}
From this structure I need the keys of the outer dictionary sorted by the sorting field of the inner dictionary, so the output is ['baguette', 'pizza', 'burger'].
Is there a simple enough way to do this?
The list.sort() method and the sorted() builtin function take a key argument, which is a function that's called for each item to be sorted, and the item is sorted based on the returnvalue of that keyfunction. So, write a function that takes a key in structure and returns the thing you want to sort on:
>>> def keyfunc(k):
... return structure[k]['sorting']
...
>>> sorted(structure, key=keyfunc)
['baguettes', 'pizza', 'burger']
You can use the sorted builtin function.
sorted(structure.keys(), key = lambda x: structure[x]['sorting'])

Categories

Resources