Convert dictionaries inside into list in nested dictionary - python

I have a dictionary like this
{'C':
{
'G':
{
'Z': '4', 'L': '1', 'P': [{'K': '3', 'B': '1'}, {'K': '7', 'B': '9'}]
}
}
}
and I'm trying to convert to list each value that is a dictionary in order to get a new dictionary like this
{'C':
[{
'G':
[{
'Z': '4', 'L': '1', 'P': [{'K': '3', 'B': '1'}, {'K': '7', 'B': '9'}]
}]
}]
}
To see it easely would be pass from dict1 to dict2
My attempt so far is like this. Thanks in advance.
>>> for k, v in d1.items():
... if isinstance(v, dict):
... d1[k,v] = d1[k,[v]]
...
Traceback (most recent call last):
File "<stdin>", line 3, in <module>
TypeError: unhashable type: 'list'

You can use recursion:
def to_list(d):
if not isinstance(d, (dict, list)):
return d
if isinstance(d, list):
return list(map(to_list, d))
return {a:to_list(b) if not isinstance(b, dict) else [to_list(b)] for a, b in d.items()}
vals = {'C': {'G': {'Z': '4', 'L': '1', 'P': [{'K': '3', 'B': '1'}, {'K': '7', 'B': '9'}]}}}
r = to_list(vals)
Output:
{'C': [{'G': [{'Z': '4', 'L': '1', 'P': [{'K': '3', 'B': '1'}, {'K': '7', 'B': '9'}]}]}]}

If you want your key to be k then you don't want d1[k,v], rather you should set d1[k] = [v]
Note that you have not provided a way to go deeper into the dictionary, this will only convert top-level values that are dicts to lists containing the dict. You'll need a way to recurse into those dicts if you wish to convert any dicts that they contain as values.

You can try recursion:
dct = {
"C": {
"G": {
"Z": "4",
"L": "1",
"P": [{"K": "3", "B": "1"}, {"K": "7", "B": "9"}],
}
}
}
def convert(d):
if isinstance(d, dict):
out = {}
for k, v in d.items():
out[k] = [convert(v)] if isinstance(v, dict) else convert(v)
return out
elif isinstance(d, list):
return [convert(v) for v in d]
return d
print(convert(dct))
Prints:
{
"C": [
{
"G": [
{
"Z": "4",
"L": "1",
"P": [{"K": "3", "B": "1"}, {"K": "7", "B": "9"}],
}
]
}
]
}

Recursive approach
d = {'C':
{
'G':
{
'Z': '4', 'L': '1', 'P': [{'K': '3', 'B': '1'}, {'K': '7', 'B': '9'}]
}
}
}
def d2l(d):
for k, v in d.items():
if isinstance(v, dict):
d2l(v)
d[k] = [v]
return d
new_dict = d2l(d)
print(new_dict)
Output
{'C': [{'G': [{'Z': '4', 'L': '1', 'P': [{'K': '3', 'B': '1'}, {'K': '7', 'B': '9'}]}]}]}

I would use recursion, this seemed to work for me:
main = {
'C': {
'G': {
'Z': '4',
'L': '1',
'P': [{'K': '3', 'B': '1'},
{'K': '7', 'B': '9'}]
}
}
}
def convert_dictionary(dictionary: dict):
for key, value in dictionary.items():
if isinstance(value, dict):
convert_dictionary(value)
dictionary[key] = [value]
convert_dictionary(main)
print(main)
Tell me if it helped!

Yet another recursion solution (added a third level)
def toList(d, d2):
for k, v in d.items():
if isinstance(v, dict):
d2[k] = [v]
toList(v, d2[k][0])
d1 = {'C':
{
'G':
{
'Z': '4', 'L': '1', 'P': [{'K': '3', 'B': '1'}],
"thirdLvl": {'K': '7', 'B': '9'}
}
}
}
d2 = {}
toList(d1,d2)
print(d2)
Result:
{'C':
[{'G':
[{'Z': '4', 'L': '1', 'P': [{'K': '3', 'B': '1'}],
'thirdLvl': [{'K': '7', 'B': '9'}]
}
]
}
]
}

Related

I tried to created dictionary in dictionary but I struggled

I tried to created a get_dict function that takes a parameter as a filename and then creates and returns a dictionary which contains
key is the number of the product code and has
value is a dictionary that contains
key is a string of sizes (S, M, L, or XL), and
value is the number of the product.
enter image description here
I tried this.
def get_dict(file_name):
d={}
e={}
with open(file_name) as f:
for line in f:
line = line.strip()
alist = line.split()
e[alist[1]] = alist[2]
d[alist[0]] = e
print (d)
the output is look like this
{'4125': {'M': '4', 'L': '7', 'XL': '3'}, '5645': {'M': '4', 'L': '7', 'XL': '3'}, '7845': {'M': '4', 'L': '7', 'XL': '3'}}
but I expect that output will be like this
{4125: {'S': 1, 'M': 4}, 5645: {'L': 7}, 9874: {'S': 8}, 9875: {'M': 8}, 7845: {'S': 10, 'XL': 3}}
Text file example
7845 XL 3
4125 S 1
5645 L 7
9874 S 3
4125 M 4
def get_dict(file_name):
d={}
with open(file_name) as f:
for line in f:
line = line.strip()
alist = line.split()
if not alist[0] in d:
d[alist[0]] = {alist[1]: alist[2]}
else:
d[alist[0]].update({alist[1]: alist[2]})
print(d)
You have to update the dictionary instead of overwriting the same key value. The above solution should work.
Output -
{'7845': {'XL': '3'}, '4125': {'S': '1', 'M': '4'}, '5645': {'L': '7'}, '9874': {'S': '3'}}

Switch key and value in a dictionary of sets

I have dictionary something like:
d1 = {'0': {'a'}, '1': {'b'}, '2': {'c', 'd'}, '3': {'E','F','G'}}
and I want result like this
d2 = {'a': '0', 'b': '1', 'c': '2', 'd': '2', 'E': '3', 'F': '3', 'G': '3'}
so I tried
d2 = dict ((v, k) for k, v in d1.items())
but value is surrounded by set{}, so it didn't work well...
is there any way that I can fix it?
You could use a dictionary comprehension:
{v:k for k,vals in d1.items() for v in vals}
# {'a': '0', 'b': '1', 'c': '2', 'd': '2', 'E': '3', 'F': '3', 'G': '3'}
Note that you need an extra level of iteration over the values in each key here to get a flat dictionary.
Another dict comprehension:
>>> {v: k for k in d1 for v in d1[k]}
{'a': '0', 'b': '1', 'c': '2', 'd': '2', 'E': '3', 'F': '3', 'G': '3'}
Benchmark comparison with yatu's:
from timeit import repeat
setup = "d1 = {'0': {'a'}, '1': {'b'}, '2': {'c', 'd'}, '3': {'E','F','G'}}"
yatu = "{v:k for k,vals in d1.items() for v in vals}"
heap = "{v:k for k in d1 for v in d1[k]}"
for _ in range(3):
print('yatu', min(repeat(yatu, setup)))
print('heap', min(repeat(heap, setup)))
print()
Results:
yatu 1.4274586000000227
heap 1.4059823000000051
yatu 1.4562267999999676
heap 1.3701727999999775
yatu 1.4313863999999512
heap 1.3878657000000203
Another benchmark, with a million keys/values:
setup = "d1 = {k: {k+1, k+2} for k in range(0, 10**6, 3)}"
for _ in range(3):
print('yatu', min(repeat(yatu, setup, number=10)))
print('heap', min(repeat(heap, setup, number=10)))
print()
yatu 1.071519999999964
heap 1.1391495000000305
yatu 1.0880677000000105
heap 1.1534022000000732
yatu 1.0944767999999385
heap 1.1526202000000012
Here's another possible solution to the given problem:
def flatten_dictionary(dct):
d = {}
for k, st_values in dct.items():
for v in st_values:
d[v] = k
return d
if __name__ == '__main__':
d1 = {'0': {'a'}, '1': {'b'}, '2': {'c', 'd'}, '3': {'E', 'F', 'G'}}
d2 = flatten_dictionary(d1)
print(d2)

Calculating min difference between two dictionaries

I'm trying to calculate difference between two dictionaries to return a specific value.
I've entered different values which should return different results, but the result remains unchanged.
diets = {"normal" : {'p': '32.50', 'c': '60', 'f': '40.86'},
"oncology" : {'p': '35', 'c': '52.50', 'f': '37.63'},
"cardiology" : {'p': '32.50', 'c': '30', 'f': '26.88'},
"diabetes" : {'p': '20', 'c': '27.50', 'f': '27.95'},
"kidney" : {'p': '15', 'c': '55', 'f': '23.65'}}
amounts = {'p': p, 'c': c, 'f': f}
value = { k : diets[k] for k in set(diets) - set(amounts) }
calculate_error = min(value)
print(calculate_error)
When i input 32, 60 and 40, the returned result should be normal, but oncology is returned instead
You should look at the values you are creating when you do this:
set(diets)
This is just a list of keys.
{'cardiology', 'diabetes', 'kidney', 'normal', 'oncology'}
When you subtract the other list of keys, you just get the original list because no values are in common.
You need to actually step through the items and do the subtraction to get the differences. Then you can find the sum of the diffs and the min of that sum.
One way would be:
diets = {"normal" : {'p': '32.50', 'c': '60', 'f': '40.86'},
"oncology" : {'p': '35', 'c': '52.50', 'f': '37.63'},
"cardiology" : {'p': '32.50', 'c': '30', 'f': '26.88'},
"diabetes" : {'p': '20', 'c': '27.50', 'f': '27.95'},
"kidney" : {'p': '15', 'c': '55', 'f': '23.65'}}
amounts = {'p': 32., 'c': 60., 'f': 40.}
mins = [(diet, sum([abs(amounts[k] - float(d[k])) for k in amounts])) for diet, d in diets.items()]
the_min = min(mins, key = lambda x: x[1])
mins will be:
[('normal', 1.3599999999999994),
('oncology', 12.869999999999997),
('cardiology', 43.620000000000005),
('diabetes', 56.55),
('kidney', 38.35)]
the_min will be:
('normal', 1.3599999999999994)
It looks you totally confused what value would be
>>> diets = {"normal" : {'p':'32.50', 'c':'60', 'f':'40.86'},
... "oncology" : {'p':'35', 'c':'52.50', 'f':'37.63'},
... "cardiology" : {'p':'32.50', 'c':'30', 'f':'26.88'},
... "diabetes" : {'p':'20', 'c':'27.50', 'f':'27.95'},
... "kidney" : {'p':'15', 'c':'55', 'f':'23.65'}}
>>> set(diets)
{'kidney', 'cardiology', 'oncology', 'normal', 'diabetes'}
>>> amounts = {'p':32, 'c':60, 'f':40}
>>> set(amounts)
{'c', 'f', 'p'}
>>> set(diets) - set(amounts)
{'cardiology', 'diabetes', 'kidney', 'oncology', 'normal'}
>>> value = { k : diets[k] for k in set(diets) - set(amounts) }
>>> value
{'cardiology': {'p': '32.50', 'c': '30', 'f': '26.88'},
'diabetes': {'p': '20', 'c': '27.50', 'f': '27.95'},
'kidney': {'p': '15', 'c': '55', 'f': '23.65'},
'oncology': {'p': '35', 'c': '52.50', 'f': '37.63'},
'normal': {'p': '32.50', 'c': '60', 'f': '40.86'}}
>>> min(value)
'cardiology'
that said I would expect that you to get cardiology, i.e. the min from diets.keys()
That said, note that the values in the diets are str, e.g. '32.50', You will need to convert these before any calculations.

How do I remove ChainMap method to save as JSON file?

I'm using ChainMap method for dictionary data and I tried to save(dumps) as a JSON file but it didn't work, and the message is that
"TypeError: Object of type 'ChainMap' is not JSON serializable"
Example:
t = [ChainMap({'a': 'ITT002', 'b': {'c': '2', 'd': '2', 'e': '2'}, 'f': '2'}, {'g': {'h1': {'i': '22', 'j': '2', 'k': '2', 'l': '2', 'n': '2'}}})]
if I have a data t, is there any ways to save in a JSON file?
Have a nice day Stack brothers!
A Chainmap groups multiple dicts and returns a view.To dump it, you have to convert it to dict.
Here is a minimal example:
import collections
import json
a = {'a': 'A', 'c': 'C'}
b = {'b': 'B', 'c': 'D'}
m = collections.ChainMap(a, b)
print(json.dumps(dict(m)))
>>{"b": "B", "a": "A", "c": "C"}
This is your specific example: You have to access the index of your list to access the ChainMap object:
t = [collections.ChainMap({'a': 'ITT002', 'b': {'c': '2', 'd': '2', 'e': '2'}, 'f': '2'}, {'g': {'h1': {'i': '22', 'j': '2', 'k': '2', 'l': '2', 'n': '2'}}})]
print(json.dumps(dict(t[0])))
>>{"f": "2", "g": {"h1": {"i": "22", "j": "2", "k": "2", "l": "2", "n": "2"}}, "b": {"c": "2", "d": "2", "e": "2"}, "a": "ITT002"}

Find biggest value in a python dict

I have a python dict like below:
{ '1': {'a': '0.6', 'b': '0.8', 'c': '2','d': '0.5'},
'2': {'a': '0.7', 'b': '0.9', 'c': '0.1','d': '0.2'},
'3': {'a': '0.5', 'b': '0.8', 'c': '3'},
}
How could I get the following result?
('2','a','0.7') ('2',b','0.9') ('3','c', '3') ('1','d', '0.5')
Well, here is the code for it (just 5 lines):
total = []
for i in ['a', 'b', 'c', 'd']:
kv = max(a.iterkeys(), key=(lambda key: float(a[key][i]) if i in a[key].keys() else -9.0))
hv = a[kv][i]
total.append((kv, i, hv))
print total
Output:
[('2', 'a', '0.7'), ('2', 'b', '0.9'), ('3', 'c', '3'), ('1', 'd', '0.5')]
-9.0 is just a random low number.
x={ '1': {'a': '0.6', 'b': '0.8', 'c': '2','d': '0.5'},
'2': {'a': '0.7', 'b': '0.9', 'c': '0.1','d': '0.2'},
'3': {'a': '0.5', 'b': '0.8', 'c': '3'},
}
d={}
for i,j in x.iteritems():
for k,m in j.iteritems():
d.setdefault(k,[0,0])
if j[k]>d[k][0]:
d[k]=(j[k],i)
print [(j[1],i,j[0]) for i,j in d.items()]
You can use additional dict to do your job.
Output:[('2', 'a', '0.7'), ('3', 'c', '3'), ('2', 'b', '0.9'), ('1', 'd', '0.5')]
I agree the question is a bit vague.. I recommend you dont use strings as values.. use int or float if you can in the dictionaries, also does not specify if python 2.x or 3.x
but I think you are after something like this..
def filter_dict(values):
result = collections.Counter()
for value in values.keys():
for k, v in values[value].items():
v = float(v)
result[k] = v if v > result[k] else result[k]
return result
this is how it behaves:
class FilterDictTest(unittest.TestCase):
def test_filter_dict(self):
# Arrange
actual = {
'1': {'a': '0.6', 'b': '0.8', 'c': '2', 'd': '0.5'},
'2': {'a': '0.7', 'b': '0.9', 'c': '0.1', 'd': '0.2'},
'3': {'a': '0.5', 'b': '0.8', 'c': '3'}
}
expected = {
'a': 0.7,
'b': 0.9,
'c': 3,
'd': 0.5
}
# Act & Assert
self.assertEquals(filter_dict(actual), expected)
A little late here.
#!/usr/bin/env python3.5
# entry
entry = {'1': {'a': '0.6', 'b': '0.8', 'c': '2','d': '0.5'}, '2': {'a': '0.7', 'b': '0.9', 'c': '0.1','d': '0.2'}, '3': {'a': '0.5', 'b': '0.8', 'c': '3'}}
# identify keys
all_categories = []
for number, dct in entry.items():
for key, val in dct.items():
all_categories = all_categories + list(dct.keys())
all_categories = set(all_categories)
# Get max values
max_values = {category:None for category in all_categories}
for category in all_categories:
for number, dct in entry.items():
if category in dct.keys():
if max_values[category] is None:
max_values[category] = (number, dct[category])
elif float(max_values[category][1]) < float(dct[category]):
max_values[category] = (number, dct[category])
output = [(number, category, value) for (category, (number, value)) in max_values.items()]
print (output)
Output:
[('2', 'a', '0.7'), ('1', 'd', '0.5'), ('2', 'b', '0.9'), ('3', 'c', '3')]
Not exactly in the order you expected them, but the values are correct. It's not the most elegant solution, though.
I iterate a second time in dict to compare values.
values = []
for key in d:
for skey in d[key]:
max = 0
_key_ = ''
for _ in d:
if d[_].has_key(skey):
if d[_][skey]>max:
max = d[_][skey]
_key_ = _
if (_key_, skey, max) not in values:
values.append((_key_, skey, max))
print values

Categories

Resources