Suppose I have 2 dictionaries:
A = {'banana':10, 'apple':2, 'pear':5, 'orange':3}
B = {'banana':7, 'orange':5, 'strawberry':4, 'blueberry':1, 'kiwi':10}
Now, I need to print all the difference of these dictionaries and display them all (even if there is a key in A that is not in B or otherwise) and of course in absolute values, so the result should be:
c = {'banana':3, 'apple':2, 'pear':5, 'orange':2, 'strawberry':4, 'blueberry':1, 'kiwi':10}
Any ideas? I've seen some posts before but only partial answers to this need.
Using collections.Counter:
from collections import Counter
A = {'banana':10, 'apple':2, 'pear':5, 'orange':3}
B = {'banana':7, 'orange':5, 'strawberry':4, 'blueberry':1, 'kiwi':10}
A_Counter, B_Counter = Counter(A), Counter(B)
print((A_Counter - B_Counter) | (B_Counter - A_Counter))
Output:
Counter({'kiwi': 10, 'pear': 5, 'strawberry': 4, 'banana': 3, 'apple': 2, 'orange': 2, 'blueberry': 1})
In py2x A.viewkeys() | B.viewkeys() will return the union of keys from both A & B, and then you can use a dict comprehension to get the desired result.
In [14]: A = {'banana':10, 'apple':2, 'pear':5, 'orange':3}
In [15]: B = {'banana':7, 'orange':5, 'strawberry':4, 'blueberry':1, 'kiwi':10}
In [16]: {x : abs( A.get(x,0) - B.get(x,0) ) for x in A.viewkeys() | B.viewkeys()}
Out[16]:
{'apple': 2,
'banana': 3,
'blueberry': 1,
'kiwi': 10,
'orange': 2,
'pear': 5,
'strawberry': 4}
For py3x use : A.keys() | B.keys()
For both py2x and py3x: set(A).union(B)
Related
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}}}
I have three dictionaries:
X = {'a':2, 'b':3,'e':4}
Y = {'c':3, 'b':4,'a':5, 'd':7}
Z = {'c':8, 'b':7,'a':9, 'e':10,'f':10}
I want to add elements of X and Y if they are present in both dicts and then subtract them from z i.e. Z-X+Y
How can I do that ?
expected result:
res = {'a':2,'b':0,'c':5,'d':7,'e':6,'f':10}
What I tried:
from collections import Counter
xy = Counter(X) + Counter(Y)
res = Counter(Z) - xy
which return:
Counter({'c': 5, 'a': 2, 'e': 6, 'f': 10})
as you can see b and d are missing from my attempt
Your expected result is actually an operation of symmetric difference in terms of sets, but since collections.Counter doesn't support such an operation, you can emulate it with:
xy = Counter(X) + Counter(Y)
z = Counter(Z)
res = z - xy | xy - z
res becomes:
Counter({'f': 10, 'd': 7, 'e': 6, 'c': 5, 'a': 2})
But if you do want keys with value of 0, which Counter would hide from its output, you would have to iterate through a union of the keys of the 3 dicts:
{k: res.get(k, 0) for k in {*X, *Y, *Z}}
This returns:
{'a': 2, 'd': 7, 'e': 6, 'b': 0, 'f': 10, 'c': 5}
A = {0:{a:1, b:7}, 1:{a:5,b:5}, 2:{a:4,b:6}}
I want to attach an item guess to each sub dictionary based on the value b accounting of all b's in each sub dictionary.
Saying, in Dictionary A:
0-b-7 percentage of b: 7/(7+5+6)
1-b-5 percentage of b: 5/(7+5+6)
2-b-6 percentage of b: 1 - 7/(7+5+6) - 5/(7+5+6)
The desired Dictionary should be like
A = {0:{a:1, b:7, 'guess': 7/(7+5+6)},
1:{a:5,b:5, 'guess': 5/(7+5+6)},
2:{a:4,b:6, 'guess': 1 - 7/(7+5+6) - 5/(7+5+6)}}
I don't know how to incorporate the other two b's for a specific subdictionary.
One approach is to precompute the sum of all bs and then use it to add a new key-value pair to your dictionary.
b_total = float(sum(A[k]['b'] for k in A))
for k in A:
A[k]['guess'] = A[k]['b'] / b_total
#{0: {'a': 1, 'b': 7, 'guess': 0.3888888888888889},
# 1: {'a': 5, 'b': 5, 'guess': 0.2777777777777778},
# 2: {'a': 4, 'b': 6, 'guess': 0.3333333333333333}}
A = {0:{"a":1, "b":7}, 1:{"a":5,"b":5}, 2:{"a":4,"b":6}}
char = "b"
denominator = 0
# =========================
# First Calculate the sum
# =========================
for key in A:
inner_map = A[key]
denominator += inner_map[char]
# ========================================
# Now insert the new key to the inner_map
# ========================================
for key in A:
inner_map = A[key]
inner_map["guess"] = inner_map[char]/denominator
print(A)
Output:
{0: {'a': 1, 'b': 7, 'guess': 0.3888888888888889}, 1: {'a': 5, 'b': 5, 'guess': 0.2777777777777778}, 2: {'a': 4, 'b': 6, 'guess': 0.3333333333333333}}
Try this:
def add_calc(my_dict):
total_guesses = sum(map(lambda x: my_dict.get(x).get('b'), my_dict))
for item in my_dict.itervalues():
item.update({'guess': 1.0 * item.get('b') / total_guesses})
return my_dict
d = add_calc(A)
{0: {'a': 1, 'b': 7, 'guess': 0.3888888888888889},
1: {'a': 5, 'b': 5, 'guess': 0.2777777777777778},
2: {'a': 4, 'b': 6, 'guess': 0.3333333333333333}}
I'm on Python 2 btw, you didn't specify version
You can use dictionary unpacking:
A = {0:{'a':1, 'b':7}, 1:{'a':5, 'b':5}, 2:{'a':4, 'b':6}}
results = {a:{**b, **{'guess':b['b']/float(sum(c['b'] for _, c in A.items()))}} for a, b in A.items()}
Output:
{0: {'guess': 0.3888888888888889, 'b': 7, 'a': 1}, 1: {'guess': 0.2777777777777778, 'b': 5, 'a': 5}, 2: {'guess': 0.3333333333333333, 'b': 6, 'a': 4}}
This question already has answers here:
Assign a number to each unique value in a list
(9 answers)
Closed 5 years ago.
I have a list, let say
L = ['apple','bat','apple','car','pet','bat'].
I want to convert it into
Lnew = [ 1,2,1,3,4,2].
Every unique string is associated with a number.
I have a java solution using hashmap, but I don't know how to use hashmap in python.
Please help.
Here's a quick solution:
l = ['apple','bat','apple','car','pet','bat']
Create a dict that maps all unique strings to integers:
d = dict([(y,x+1) for x,y in enumerate(sorted(set(l)))])
Map each string in the original list to its respective integer:
print [d[x] for x in l]
# [1, 2, 1, 3, 4, 2]
x = list(set(L))
dic = dict(zip(x, list(range(1,len(x)+1))))
>>> [dic[v] for v in L]
[1, 2, 1, 3, 4, 2]
You can use a map dictionary:
d = {'apple':1, 'bat':2, 'car':3, 'pet':4}
L = ['apple','bat','apple','car','pet','bat']
[d[x] for x in L] # [1, 2, 1, 3, 4, 2]
For auto creating map dictionary you can use defaultdict(int) with a counter.
from collections import defaultdict
d = defaultdict(int)
co = 1
for x in L:
if not d[x]:
d[x] = co
co+=1
d # defaultdict(<class 'int'>, {'pet': 4, 'bat': 2, 'apple': 1, 'car': 3})
Or as #Stuart mentioned you can use d = dict(zip(set(L), range(len(L)))) for creating dictionary
You'd use a hashmap in Python, too, but we call it a dict.
>>> L = ['apple','bat','apple','car','pet','bat']
>>> idx = 1
>>> seen_first = {}
>>>
>>> for word in L:
... if word not in seen_first:
... seen_first[word] = idx
... idx += 1
...
>>> [seen_first[word] for word in L]
[1, 2, 1, 3, 4, 2]
You can try:
>>> L = ['apple','bat','apple','car','pet','bat']
>>> l_dict = dict(zip(set(L), range(len(L))))
>>> print l_dict
{'pet': 0, 'car': 1, 'bat': 2, 'apple': 3}
>>> [l_dict[x] for x in L]
[3, 2, 3, 1, 0, 2]
Lnew = []
for s in L:
Lnew.append(hash(s)) # hash(x) returns a unique int based on string
I have two lists:
L1 = ['A','B','A','C','A']
L2 = [1, 4, 6, 1, 3]
I want to create a dictionary which has the following output:
DictOutSum = {'A':10, 'B':4, 'C':1}
DictOutCount = {'A':3, 'B':1, 'C':1}
i.e. Lists L1 and L2 both have same number of elements and the elements in them corresponds one to one. I want to find sum of all numbers in L2 for each unique element in L1 and make a dictionary out of it(DictOutSum). I also want to create another dictionary which stores the counts of number of unique elements of L1(DictOutCount).
I don't even have an idea where to start for this other than to use a for loop.
Pure python implementation:
>>> dict_sum = dict.fromkeys(L1, 0)
>>> dict_count = dict.fromkeys(L1, 0)
>>> for k,n in zip(L1, L2):
... dict_sum[k] += n
... dict_count[k] += 1
...
>>> dict_sum
{'A': 10, 'B': 4, 'C': 1}
>>> dict_count
{'A': 3, 'B': 1, 'C': 1}
Fancy one-liner implementations:
>>> from collections import Counter
>>> Counter(L1) # dict_count
Counter({'A': 3, 'B': 1, 'C': 1})
>>> sum((Counter({k:v}) for k,v in zip(L1, L2)), Counter()) # dict_sum
Counter({'A': 10, 'B': 4, 'C': 1})
You should use the zip builtin function
import collections
DictOutSum = collections.defaultdict(int)
DictOutCount = collections.defaultdict(int)
for l1, l2 in zip(L1, L2):
DictOutSum[l1] += l2
DictOutCount[l1] += 1
>>> L1 = ['A','B','A','C','A']
>>> L2 = [1, 4, 6, 1, 3]
>>>
>>> DictOutCount = {v:0 for v in L1}
>>> DictOutSum = {v:0 for v in L1}
>>> for v1,v2 in zip(L1,L2):
... DictOutCount[v1] += 1
... DictOutSum[v1] += v2
...
>>>
>>> DictOutCount
{'A': 3, 'C': 1, 'B': 1}
>>> DictOutSum
{'A': 10, 'C': 1, 'B': 4}
>>>
The mega elementary way
L1 = ['A','B','A','C','A']
L2 = [1, 4, 6, 1, 3]
# Carries the information
myDict = {}
# Build the dictionary
for x in range(0,len(L1)):
# Initialize the dictionary IF the key doesn't exist
if L1[x] not in myDict:
myDict[L1[x]] = {}
myDict[L1[x]]['sum'] = 0
myDict[L1[x]]['count'] = 0
# Collect the information you need
myDict[L1[x]][x] = L2[x]
myDict[L1[x]]['sum'] += L2[x]
myDict[L1[x]]['count'] += 1
# Build the other two dictionaries
DictOutSum = {}
DictOutCount = {}
# Literally feed the data
for element in myDict:
DictOutSum[element] = myDict[element]['sum']
DictOutCount[element] = myDict[element]['count']
print DictOutSum
# {'A': 10, 'C': 1, 'B': 4}
print DictOutCount
# {'A': 3, 'C': 1, 'B': 1}
Side note: From your username, are you Persian?
DictOutCount, use collections.Counter,
import collections
DictOutCount = collections.Counter(L1)
print(DictOutCount)
Counter({'A': 3, 'C': 1, 'B': 1})
DictOutSum,
DictOutSum = dict()
for k, v in zip(L1, L2):
DictOutSum[k] = DictOutSum.get(k, 0) + v
print(DictOutSum)
# Output
{'A': 10, 'C': 1, 'B': 4}
Previous answer, DictOutSum,
import itertools
import operator
import functools
DictOutSum = dict()
for name, group in itertools.groupby(sorted(itertools.izip(L1, L2)), operator.itemgetter(0)):
DictOutSum[name] = functools.reduce(operator.add, map(operator.itemgetter(1), group))
print(DictOutSum)
{'A': 10, 'C': 1, 'B': 4}
The main steps are:
use itertools.izip to make an iterator that aggregates elements from each of L1 and L2
use itertools.groupby to make an iterator that returns consecutive keys and groups from the iterable (sorting before that)
use functools.reduce for cumulatively addition