Subdivide python dict [duplicate] - python

This question already has answers here:
How do I create a nested dict from a dict by splitting the keys on a delimiter in python?
(4 answers)
Closed 1 year ago.
I want to write a method which takes a dict in the form of {a: 1, b-c: 2, b-d: 3, e-f-g: 4} and returns {a: 1, b: {c: 2, d: 3}, e: {f: {g: 4}}}. Basically split the keys containing - into subdicts. I've tried to do it iteratively and recursively but I got stuck. Any tips?

You can use collections.defaultdict with recursion:
from collections import defaultdict
d = {'a': 1, 'b.c': 2, 'b.d': 3, 'e.f.g': 4}
def group(d):
nd = defaultdict(list)
for [a, *b], c in d:
nd[a].append([b, c])
return {a:b[0][-1] if not any(j for j, _ in b) else group(b) for a, b in nd.items()}
result = group([[a.split('.'), b] for a, b in d.items()])
Output:
{'a': 1, 'b': {'c': 2, 'd': 3}, 'e': {'f': {'g': 4}}}

Related

Adding to a dictionary based on key and value from lists?

I have a dictionary defined as:
letters = {'a': 2, 'b': 1, 'c': 5}
I want to add values to this dictionary based on two lists: one which contains the keys and another which contains the values.
key_list = [a, c]
value_list = [2, 5]
This should give the output:
{a: 4, b: 1, c: 10}
Any ideas on how I can accomplish this? I am new to working with the dictionary structure so I apologise if this is extremely simple.
Thanks.
You can zip the two lists and then add to the dictionary as so;
letters = {'a': 2, 'b': 1, 'c': 5}
key_list = ['a', 'c']
value_list = [2, 5]
for k,v in zip(key_list, value_list):
letters[k] = letters.get(k, 0) + v
Using the dictionary's get() method as above allows you to add letters that aren't already in the dictionary.
for i in range(len(key_list)):
letters[key_list[i]] += value_list[i]
You can simply add or modify values from a dictionary using the key
For example:
letters = {'a': 2, 'b':1 , 'c': 5}
letters['a'] += 2
letters['c'] += 5
print(letters)
output = {'a': 4, 'b': 1, 'c': 10}

Nesting dictionary algorithm

Suppose I have the following dictionary:
{'a': 0, 'b': 1, 'c': 2, 'c.1': 3, 'd': 4, 'd.1': 5, 'd.1.2': 6}
I wish to write an algorithm which outputs the following:
{
"a": 0,
"b": 1,
"c": {
"c": 2,
"c.1": 3
},
"d":{
"d": 4,
"d.1": {
"d.1": 5,
"d.1.2": 6
}
}
}
Note how the names are repeated inside the dictionary. And some have variable level of nesting (eg. "d").
I was wondering how you would go about doing this, or if there is a python library for this? I know you'd have to use recursion for something like this, but my recursion skills are quite poor. Any thoughts would be highly appreciated.
You can use a recursive function for this or just a loop. The tricky part is wrapping existing values into dictionaries if further child nodes have to be added below them.
def nested(d):
res = {}
for key, val in d.items():
t = res
# descend deeper into the nested dict
for x in [key[:i] for i, c in enumerate(key) if c == "."]:
if x in t and not isinstance(t[x], dict):
# wrap leaf value into another dict
t[x] = {x: t[x]}
t = t.setdefault(x, {})
# add actual key to nested dict
if key in t:
# already exists, go one level deeper
t[key][key] = val
else:
t[key] = val
return res
Your example:
d = {'a': 0, 'b': 1, 'c': 2, 'c.1': 3, 'd': 4, 'd.1': 5, 'd.1.2': 6}
print(nested(d))
# {'a': 0,
# 'b': 1,
# 'c': {'c': 2, 'c.1': 3},
# 'd': {'d': 4, 'd.1': {'d.1': 5, 'd.1.2': 6}}}
Nesting dictionary algorithm ...
how you would go about doing this,
sort the dictionary items
group the result by index 0 of the keys (first item in the tuples)
iterate over the groups
if there are is than one item in a group make a key for the group and add the group items as the values.
Slightly shorter recursion approach with collections.defaultdict:
from collections import defaultdict
data = {'a': 0, 'b': 1, 'c': 2, 'c.1': 3, 'd': 4, 'd.1': 5, 'd.1.2': 6}
def group(d, p = []):
_d, r = defaultdict(list), {}
for n, [a, *b], c in d:
_d[a].append((n, b, c))
for a, b in _d.items():
if (k:=[i for i in b if i[1]]):
r['.'.join(p+[a])] = {**{i[0]:i[-1] for i in b if not i[1]}, **group(k, p+[a])}
else:
r[b[0][0]] = b[0][-1]
return r
print(group([(a, a.split('.'), b) for a, b in data.items()]))
Output:
{'a': 0, 'b': 1, 'c': {'c': 2, 'c.1': 3}, 'd': {'d': 4, 'd.1': {'d.1': 5, 'd.1.2': 6}}}

Merge 2 dictionaries with higher value for each key [duplicate]

This question already has answers here:
keep highest value of duplicate keys in dicts
(6 answers)
Closed 2 years ago.
I have
dict1 = {a: 1, b: 2, c: 3}
dict2 = {b: 3, c: 2}
How do I merge dict1 and dict2 so that the result dict3 will have {a: 1, b: 3, c: 3}
I know we can merge like this dict3 = {**a, **b}, but is there a condition anywhere I have to write to make it work for my problem?
Here you go:
dict1 = {"a": 1, "b": 2, "c": 3}
dict2 = {"b": 3, "c": 2}
result = {}
for k in dict1.keys() | dict2.keys():
result[k] = max(dict1.get(k, float('-inf')), dict2.get(k,float('-inf')))
print(result)
I am using a get with default: dict1.get(k, DEFAULT) and joining the two keysets with the bitwise OR operator |.
Note that the default of float('-inf') means the result for
dict1 = {"a": -1, "b": 2, "c": 3}
dict2 = {"b": -5, "c": 2}```
becomes {'a': -1, 'b': 2, 'c': 3}.
While for the default of 0 you would get
{'b': 2, 'c': 3, 'a': 0}
Both ways could be considered equally valid responses.
You can merge the dict items into one sequence of tuples, sort them, and then use the dict constructor to create a new dict from the sorted sequence so that items of the same keys but with higher values will override those with lower values:
dict(sorted((*dict1.items(), *dict2.items())))
You could simply loop through them and compare the values, and use dict.setdefault(key, 0) to get around unset values.
dict1 = {'a': 1, 'b': 2, 'c': 3}
dict2 = {'b': 3, 'c': 2}
dict3 = {}
for d in dict1, dict2:
for k, v in d.items():
if v > dict3.setdefault(k, 0):
dict3[k] = v
print(dict3) # -> {'a': 1, 'b': 3, 'c': 3}
defaultdict(int) would also work but I wanted to avoid the import.

Iterate over X dictionary items in Python

How can I iterate over only X number of dictionary items? I can do it using the following bulky way, but I am sure Python allows a more elegant way.
d = {'a': 1, 'b': 2, 'c': 3, 'd': 4, 'e': 5}
x = 0
for key in d:
if x == 3:
break
print key
x += 1
If you want a random sample of X values from a dictionary you can use random.sample on the dictionary's keys:
from random import sample
d = {'a': 1, 'b': 2, 'c': 3, 'd': 4, 'e': 5}
X = 3
for key in sample(d, X):
print key, d[key]
And get output for example:
e 5
c 3
b 2

Python - Adding two dictionaries [duplicate]

This question already has answers here:
Is there any pythonic way to combine two dicts (adding values for keys that appear in both)?
(22 answers)
Closed 5 years ago.
How to add the values of two dictionary ?
Ex :
a = {'a':10,'b':11,'c':20}
b = {'a':1,'b':1,'c':1}
result must be
c = {'a':11,'b':12,'c':21}
You can easily add two dictionaries by using Counter class of collections library for ex:
from collections import Counter
a = {'a':10,'b':11,'c':20}
b = {'a':1,'b':1,'c':1}
a = Counter(a)
b = Counter(b)
c = dict(a + b)
print c
OUTPUT
{'c': 21, 'b': 12, 'a': 11}
Next some please show some effort..
a = {'a':10,'b':11,'c':20}
b = {'a':1,'b':1,'c':1}
c = {k: a[k] + b[k] for k in a}
print(c) # {'c': 21, 'b': 12, 'a': 11}
The above works fine if we assume that a and b have the same keys.
If that is not the case, you can try the following:
a = {'a': 10, 'b': 11, 'c': 20, 'h': 5}
b = {'a': 1, 'b': 1, 'c': 1, 'd': 12}
all_keys = set(a.keys()) # in Python 3 it can be simplified as `all_keys = set(a)`
all_keys.update(b.keys()) # in Python 3 it can be simplified as `all_keys.update(b)`
c = {k: a.get(k, 0) + b.get(k, 0) for k in all_keys}
print(c) # {'c': 21, 'h': 5, 'a': 11, 'b': 12, 'd': 12}
Notice that i am using get on both dictionaries to skip the check on the existence of the key.

Categories