Access Key of Dictionary inside self - python

Is it possible to access the key of a dictionary inside of the same dictionary?
For example, I know this doesn't work, but I want to do something like this:
d = {
'a': 1,
'b': 2,
'c': d['a'] + d['b'] # or actually more like: self.a + self.b
}
print(d['c']) # 3

You have to add the derived (key, value) pairs after contructing the dict.
d = {
'a': 1,
'b': 2
}
d['c'] = d['a'] + d['b']

Related

Creating Nested dictionary with multiple hierarchy separated with '.'

I'm trying to create a multiple hierarchy of nested dictionary. The hierarchy levels are separated with a dot(.) in variable B however the final key (A) and value (D) are fixed.
Variables
A = "key"
B = "one.two.three.four"
D = "value"
Desired Output
{ one : { two : {three : {four : {key: value}}}}}
Here, the length of hierarchy (variable B) might increase or decrease based on input. I'm unable to create such dynamic code.
My pseudocode Code
A = "key"
B = "one.two.three.four"
D = "value"
inner_dictionary = {}
whole_dictionary = {}
lst = B.split('.')
length = len(lst)
for i in range(length):
new = lst[-1]
tmp = {A:D}
inner_dictionary.update(tmp)
val = { new : inner_dictionary}
whole_dictionary.update(val)
lst.pop()
print(whole_dictionary)
My Output
{'four': {'key': 'value'}, 'three': {'key': 'value'}, 'two': {'key': 'value'}, 'one': {'key': 'value'}}
I need help on this. Thanks in advance!
Use this:
A = "key"
B = "one.two.three.four"
D = "value"
x = {A: D}
for k in B.split('.')[::-1]:
x = {k: x}
print(x)
Output:
{'one': {'two': {'three': {'four': {'key': 'value'}}}}}
Or, in Python 3.8+, using the walrus operator:
A = "key"
B = "one.two.three.four"
D = "value"
x = {A: D}
[(x := {k: x}) for k in B.split('.')[::-1]]
print(x)
Output:
{'one': {'two': {'three': {'four': {'key': 'value'}}}}}
Note: the second solution takes a lot more time (you can run the following code to check that):
from timeit import timeit
print(timeit("""A = "key"
B = "one.two.three.four"
D = "value"
x = {A: D}
for k in B.split('.')[::-1]:
x = {k: x}"""))
print(timeit("""A = "key"
B = "one.two.three.four"
D = "value"
x = {A: D}
[(x := {k: x}) for k in B.split('.')[::-1]]"""))
The first one takes about 0.5s, the second one about 1s.
One approach using a single for-loop:
A = "key"
B = "one.two.three.four"
D = "value"
start = { A: D }
for k in reversed(B.split(".")):
start = { k : start }
print(start)
Output
{'one': {'two': {'three': {'four': {'key': 'value'}}}}}
This type of problem where a list of values aggregates to a single one can be solved using reduce (a la functional programming):
from functools import reduce
A = "key"
B = "one.two.three.four"
D = "value"
res = reduce(lambda x, y: {y: x}, reversed(B.split(".")), {A: D})

Delete a key in a JSON object, and add a different key

So, at one point in my AWS Lambda function (python), I have a JSON object like this:
[{"a":1, "b":2},
{"a":3, "b":4},
{"a":5, "b":6}]
Now, from this JSON object, I want to remove the a key from all, and want to add a constant c key to all.
I.e my final JSON object should look like this:
[{"b":2, "c":10},
{"b":4, "c":10},
{"b":6, "c":10}]
How should I achieve this?
obj = [{"a":1, "b":2},
{"a":3, "b":4},
{"a":5, "b":6}]
new_obj = [{ **{k:v for k,v in d.items() if k != "a"}, # remove "a" key
**{"c":10}} # add "c" constant
for d in obj]
print(new_obj)
# [{'b': 2, 'c': 10}, {'b': 4, 'c': 10}, {'b': 6, 'c': 10}]
You can traverse through the list and use the pop command to remove the a key. The below code should help you do that as well as add the constant c key to all
for dict_obj in obj:
dict_obj.pop('a', None)
dict_obj['c'] = 10

Getting the difference (in values) between two dictionaries in python

Let's say you are given 2 dictionaries, A and B with keys that can be the same but values (integers) that will be different. How can you compare the 2 dictionaries so that if the key matches you get the difference (eg if x is the value from key "A" and y is the value from key "B" then result should be x-y) between the 2 dictionaries as a result (preferably as a new dictionary).
Ideally you'd also be able to compare the gain in percent (how much the values changed percentage-wise between the 2 dictionaries which are snapshots of numbers at a specific time).
Given two dictionaries, A and B which may/may not have the same keys, you can do this:
A = {'a':5, 't':4, 'd':2}
B = {'s':11, 'a':4, 'd': 0}
C = {x: A[x] - B[x] for x in A if x in B}
Which only subtracts the keys that are the same in both dictionaries.
You could use a dict comprehension to loop through the keys, then subtract the corresponding values from each original dict.
>>> a = {'a': 5, 'b': 3, 'c': 12}
>>> b = {'a': 1, 'b': 7, 'c': 19}
>>> {k: b[k] - a[k] for k in a}
{'a': -4, 'b': 4, 'c': 7}
This assumes both dict have the exact same keys. Otherwise you'd have to think about what behavior you expect if there are keys in one dict but not the other (maybe some default value?)
Otherwise if you want to evaluate only shared keys, you can use the set intersection of the keys
>>> {k: b[k] - a[k] for k in a.keys() & b.keys()}
{'a': -4, 'b': 4, 'c': 7}
def difference_dict(Dict_A, Dict_B):
output_dict = {}
for key in Dict_A.keys():
if key in Dict_B.keys():
output_dict[key] = abs(Dict_A[key] - Dict_B[key])
return output_dict
>>> Dict_A = {'a': 4, 'b': 3, 'c':7}
>>> Dict_B = {'a': 3, 'c': 23, 'd': 2}
>>> Diff = difference_dict(Dict_A, Dict_B)
>>> Diff
{'a': 1, 'c': 16}
If you wanted to fit that all onto one line, it would be...
def difference_dict(Dict_A, Dict_B):
output_dict = {key: abs(Dict_A[key] - Dict_B[key]) for key in Dict_A.keys() if key in Dict_B.keys()}
return output_dict
If you want to get the difference of similar keys into a new dictionary, you could do something like the following:
new_dict={}
for key in A:
if key in B:
new_dict[key] = A[key] - B[key]
...which we can fit into one line
new_dict = { key : A[key] - B[key] for key in A if key in B }
here is a python package for this case:
https://dictdiffer.readthedocs.io/en/latest/
from dictdiffer import diff
print(list(diff(a, b)))
would do the trick.

getting a dictionary of class variables and values

I am working on a method to return all the class variables as keys and values as values of a dictionary , for instance i have:
first.py
class A:
a = 3
b = 5
c = 6
Then in the second.py i should be able to call maybe a method or something that will return a dictionary like this
import first
dict = first.return_class_variables()
dict
then dict will be something like this:
{'a' : 3, 'b' : 5, 'c' : 6}
This is just a scenario to explain the idea, of course i don't expect it to be that easy, but i will love if there are ideas on how to handle this problem just like dict can be used to set a class variables values by passing to it a dictionary with the variable, value combination as key, value.
You need to filter out functions and built-in class attributes.
>>> class A:
... a = 3
... b = 5
... c = 6
...
>>> {key:value for key, value in A.__dict__.items() if not key.startswith('__') and not callable(key)}
{'a': 3, 'c': 6, 'b': 5}
Something like this?
class A(object):
def __init__(self):
self.a = 3
self.b = 5
self.c = 6
def return_class_variables(A):
return(A.__dict__)
if __name__ == "__main__":
a = A()
print(return_class_variables(a))
which gives
{'a': 3, 'c': 6, 'b': 5}
Use a dict comprehension on A.__dict__ and filter out keys that start and end with __:
>>> class A:
a = 3
b = 5
c = 6
...
>>> {k:v for k, v in A.__dict__.items() if not (k.startswith('__')
and k.endswith('__'))}
{'a': 3, 'c': 6, 'b': 5}
Best solution and most pythonic is to use var(class_object) or var(self) (if trying to use inside class).
This although do avoids dictionary pairs where the key is another object and not a default python type.
>>> class TheClass():
>>> def __init__(self):
>>> self.a = 2
>>> self.b = 1
>>> print(vars(self))
>>> class_object= TheClass()
{'a'=2, 'b'=1}
Or outside class
>>> vars(class_object)
{'a': 2, 'b': 1}
You can use __dict__ to get the list of a class variables. For example, if you have a class like this:
class SomeClass:
def __init__(self, a, b, c):
self.a = a
self.b = b
self.c = c
def to_dict(self) -> dict:
return {key: value for key, value in self.__dict__.items()}
You can get the list of variables this way:
some_class = SomeClass(1,2,3)
some_class.to_dict()
And the output will be:
{'a':1, 'b':2, 'c':3}

Python reversing nested dictionaries

I want to take a nested dictionary and reverse the values
for example
input = { "a" : { "x": 2, "y": 3 },
"b" : { "x": 5, "z": 7 } }
output = {'y': {'a': 3},
'x': {'a': 2, 'b': 5},
'z': {'b': 7} }
what I have:
def reverse_nest_dicts(nested_dict):
reverse_nest_dict = {}
for k, v in nested_dict:
for k2, v2 in nested_dict.values():
reverse_nest_dict[k2][k] = v2
return reverse_nest_dict
for k2, v2 in nested_dict.values():
should be
for k2, v2 in v.items():
(Also note that if you're using Python 2.x, it may be more efficient to use .iteritems() instead of .items().)
You also need to make sure the sub-dictionaries are initialized - you can do this by either using defaultdict...
from collections import defaultdict
reverse_nest_dict = defaultdict(dict)
...or by using setdefault:
reverse_nest_dict.setdefault(k2, {})[k] = v2
Your function has three different errors. The following is what you are after:
def reverse_nest_dicts(nested_dict):
reverse_nest_dict = {}
for k, v in nested_dict.iteritems():
for k2, v2 in v.iteritems():
try:
reverse_nest_dict[k2][k] = v2
except KeyError:
reverse_nest_dict[k2] = { k : v2 }
return reverse_nest_dict
The errors are:
1st for loop: using the dictionary as loop sequence will result in keys only, you want (key,value) so need to use items() or iteritems()
2nd for loop: the loop sequence should be the nested dictionary, not the outer dictionary
you need to initialise the reverse_nest_dict values to inner dictionaries before you try to access them.
The dictionary items() and setdefault() methods make short work of this kind of problem:
>>> input = { "a" : { "x": 2, "y": 3 },
"b" : { "x": 5, "z": 7 } }
>>> result = {}
>>> for k1, subdict in input.items():
for k2, v in subdict.items():
result.setdefault(k2, {})[k1] = v
>>> result
{'y': {'a': 3}, 'x': {'a': 2, 'b': 5}, 'z': {'b': 7}}
In Python 2, you can get a minor speed boost by using iteritems() instead of items().
Likewise, the use of collections.defaultdict(dict) can be a little faster than using setdefault. Of course, that will return a defaultdict instead of a dict as specified in your question.
If the dictionary is too large, check https://stackoverflow.com/a/47151034/676214
If you want just access reverse nested dictionaries,
Save memory if the dictionary is too large to reverse.
class mdict2(dict):
def __init__(self, parent, key1):
self.parent = parent
self.key1 = key1
def __getitem__(self, key2):
return self.parent.mirror[key2][self.key1]
class mdict(dict):
def __init__(self, mirror):
self.mirror = mirror
def __getitem__(self, key):
return mdict2(self, key)
d0 = {
'Bob' : {'item1':3, 'item2':8, 'item3':6},
'Jim' : {'item1':6, 'item4':7},
'Amy' : {'item1':6,'item2':5,'item3':9,'item4':2}
}
d1 = mdict(d0)
d0['Amy']['item1'] == d1['item1']['Amy']
# True
Use NestedDict. First install ndicts
pip install ndicts
Then
from ndicts.ndicts import NestedDict
input_dict = {"a": { "x": 2, "y": 3 }, "b": { "x": 5, "z": 7 }}
nd = NestedDict(input_dict)
reversed_nd = NestedDict()
for key, value in nd.items():
reversed_key = tuple(reversed(key))
reversed_nd[reversed_key] = value
Finally
>>> reversed_nd.to_dict()
{'x': {'a': 2, 'b': 5}, 'y': {'a': 3}, 'z': {'b': 7}}

Categories