Related
Invoice
[{'A': 5, 'B': 10, 'C': 15}, {'A': 5, 'B': 25, 'C': 17, 'D': 30, }]
Bank
[{'A': 5, 'G': 10, 'Q': 15}, {'A': 5, 'B': 25, 'M': 17, 'T': 30, }]
After merge
Answer
[{'A':10,'B':10,'C':15,'G':10,'Q':15},{'A':10,'B':50,'C':17,'D':30,'M':17,'T':30}]
Try using collections.Counter to merge the counts between both paired dictionaries created from zip:
from collections import Counter
l1 = [{'A': 5, 'B': 10, 'C': 15}, {'A': 5, 'B': 25, 'C': 17, 'D': 30, }]
l2 = [{'A': 5, 'G': 10, 'Q': 15}, {'A': 5, 'B': 25, 'M': 17, 'T': 30, }]
result = [Counter(x) + Counter(y) for x, y in zip(l1, l2)]
print(result)
Output:
[Counter({'C': 15, 'Q': 15, 'A': 10, 'B': 10, 'G': 10}), Counter({'B': 50, 'D': 30, 'T': 30, 'C': 17, 'M': 17, 'A': 10})]
Counter is a subclass of dict, so you can treat it like a normal dictionary. You can cast it to dict if you want your result to look like [{'A': 10, 'B': 10, 'C': 15, 'G': 10, 'Q': 15}, {'A': 10, 'B': 50, 'C': 17, 'D': 30, 'M': 17, 'T': 30}].
Why the above works from the docs:
Several mathematical operations are provided for combining Counter objects to produce multisets (counters that have counts greater than zero). Addition and subtraction combine counters by adding or subtracting the counts of corresponding elements. Intersection and union return the minimum and maximum of corresponding counts. Each operation can accept inputs with signed counts, but the output will exclude results with counts of zero or less.
I have a list of names and a list of the alphabet. I am able to determine the number of a single letter at a time. How do I check make python go through my entire alphabet list and append them in order.
listOfNames = ["Euclid", "Archimedes", "Newton", "Descartes", "Fermat", "Turing",
"Euler", "Einstein", "Boole", "Fibonacci", "Lovelace", "Noether",
"Nash", "Wiles", "Cantor", "Gauss", "Plato"]
alphaList = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z']
alphaCount = []
letterCount = 0
for names in listOfNames:
for letter in names:
if letter.lower() in alphaList[0]:
letterCount += 1
alphaCount.append(letterCount)
print(alphaCount)
Outcome == [9]
expected outcome == [9, 2,.....] #number of 'a's , number of 'b's...etc
You could modify your code to instead produce a dictionary of counts for each letter
alphaCount = {}
for name in listOfNames:
for letter in name:
letter_lower = letter.lower()
if letter_lower in alphaCount:
alphaCount[letter_lower] += 1
else:
alphaCount[letter_lower] = 1
Result
>>> alphaCount
{'e': 17, 'u': 4, 'c': 7, 'l': 7, 'i': 8, 'd': 3, 'a': 9, 'r': 7, 'h': 3, 'm': 2, 's': 8, 'n': 9, 'w': 2, 't': 8, 'o': 8, 'f': 2, 'g': 2, 'b': 2, 'v': 1, 'p': 1}
If you want a list of counts in alphabetical order, you can use this dictionary in a list comprehension
>>> [alphaCount.get(i, 0) for i in alphaList]
[9, 2, 7, 3, 17, 2, 2, 3, 8, 0, 0, 7, 2, 9, 8, 1, 0, 7, 8, 8, 4, 1, 2, 0, 0, 0]
A much simpler code with defaultdict. Try this:
from collections import defaultdict
listOfNames = ["Euclid", "Archimedes", "Newton", "Descartes", "Fermat", "Turing",
"Euler", "Einstein", "Boole", "Fibonacci", "Lovelace", "Noether",
"Nash", "Wiles", "Cantor", "Gauss", "Plato"]
di = defaultdict(int)
for name in listOfNames:
for letter in name:
di[letter.lower()] += 1
print(dict(di))
Outputs:
{'e': 17, 'u': 4, 'c': 7, 'l': 7, 'i': 8, 'd': 3, 'a': 9, 'r': 7, 'h': 3, 'm': 2, 's': 8, 'n': 9, 'w': 2, 't': 8, 'o': 8, 'f': 2, 'g': 2, 'b': 2, 'v': 1, 'p': 1}
EDITED:
I won't say it is the most efficient solution but it works. To generate a list of alphabets, I have used string.ascii_lowercase in string module.
from collections import defaultdict
import string
listOfNames = ["Euclid", "Archimedes", "Newton", "Descartes", "Fermat", "Turing",
"Euler", "Einstein", "Boole", "Fibonacci", "Lovelace", "Noether",
"Nash", "Wiles", "Cantor", "Gauss", "Plato"]
di = defaultdict(int)
for name in listOfNames:
for letter in name:
di[letter.lower()] += 1
alphaCount = [dict(di).get(i, 0) for i in list(string.ascii_lowercase)]
print(alphaCount)
Outputs:
[9, 2, 7, 3, 17, 2, 2, 3, 8, 0, 0, 7, 2, 9, 8, 1, 0, 7, 8, 8, 4, 1, 2, 0, 0, 0]
You can try this.
from itertools import chain
from collections import Counter
list_name=map(str.lower,listOfNames)
out=Counter(chain.from_iterable(list_name))
# Counter({'e': 17, 'a': 9, 'n': 9, 'i': 8, 's': 8, 't': 8, 'o': 8, 'c': 7, 'l': 7, 'r': 7, 'u': 4, 'd': 3, 'h': 3, 'm': 2, 'w': 2, 'f': 2, 'g': 2, 'b': 2, 'v': 1, 'p': 1})
To get in alphabetical order of counts
[out[k] for k in alphaList]
# [9, 2, 7, 3, 17, 2, 2, 3, 8, 0, 0, 7, 2, 9, 8, 1, 0, 7, 8, 8, 4, 1, 2, 0, 0, 0]
a combination of join and Counter would be a good solution
listOfNames = ["Euclid", "Archimedes", "Newton", "Descartes", "Fermat", "Turing",
"Euler", "Einstein", "Boole", "Fibonacci", "Lovelace", "Noether",
"Nash", "Wiles", "Cantor", "Gauss", "Plato"]
r = "".join(listOfNames).lower()
from collections import Counter
sol = Counter(r)
print(sol)
output
Counter({'e': 17, 'a': 9, 'n': 9, 'i': 8, 's': 8, 't': 8, 'o': 8, 'c': 7, 'l': 7, 'r': 7, 'u': 4, 'd': 3, 'h': 3, 'm': 2, 'w': 2, 'f': 2, 'g': 2, 'b': 2, 'v': 1, 'p': 1})
way 2 using while
# your code goes here
listOfNames = ["Euclid", "Archimedes", "Newton", "Descartes", "Fermat", "Turing",
"Euler", "Einstein", "Boole", "Fibonacci", "Lovelace", "Noether",
"Nash", "Wiles", "Cantor", "Gauss", "Plato"]
length = len(listOfNames)
count = 0
solution = {'a': 0, 'b': 0, 'c': 0, 'd': 0, 'e': 0,
'f': 0, 'g': 0, 'h': 0, 'i': 0, 'j': 0, 'k': 0,
'l': 0, 'm': 0, 'n': 0, 'o': 0, 'p': 0, 'q': 0,
'r': 0, 's': 0, 't': 0,
'u': 0, 'v': 0, 'w': 0, 'x': 0, 'y': 0, 'z': 0}
while count<length:
for character in listOfNames[count]:
solution[character.lower()]+=1
count+=1
print(solution)
output
{'a': 9, 'b': 2, 'c': 7, 'd': 3, 'e': 17,
'f': 2, 'g': 2, 'h': 3, 'i': 8, 'j': 0,
'k': 0, 'l': 7, 'm': 2, 'n': 9, 'o': 8,
'p': 1, 'q': 0, 'r': 7, 's': 8, 't': 8,
'u': 4, 'v': 1, 'w': 2, 'x': 0, 'y': 0,
'z': 0}
Currently, I have a dictionary, with its key representing a zip code, and the values are also a dictionary.
d = { 94111: {'a': 5, 'b': 7, 'd': 7},
95413: {'a': 6, 'd': 4},
84131: {'a': 5, 'b': 15, 'c': 10, 'd': 11},
73173: {'a': 15, 'c': 10, 'd': 15},
80132: {'b': 7, 'c': 7, 'd': 7} }
And then a second dictionary, which associates which state the zip code belongs to.
states = {94111: "TX", 84131: "TX", 95413: "AL", 73173: "AL", 80132: "AL"}
If the zip code in the dictionary states matches one of the keys in db then it would sum up those values and put it into a new dictionary like the expected output.
Expected Output:
{'TX': {'a': 10, 'b': 22, 'd': 18, 'c': 10}, 'AL': {'a': 21, 'd': 26, 'c': 17, 'b': 7}}
So far this is the direction I am looking to go into but I'm not sure when both the keys match, how to create a dictionary that will look like the expected output.
def zips(d, states):
result = dict()
for key, value in db.items():
for keys, values in states.items():
if key == keys:
zips(d, states)
Using collections module
Ex:
from collections import defaultdict, Counter
d = { 94111: {'a': 5, 'b': 7, 'd': 7},
95413: {'a': 6, 'd': 4},
84131: {'a': 5, 'b': 15, 'c': 10, 'd': 11},
73173: {'a': 15, 'c': 10, 'd': 15},
80132: {'b': 7, 'c': 7, 'd': 7} }
states = {94111: "TX", 84131: "TX", 95413: "AL", 73173: "AL", 80132: "AL"}
result = defaultdict(Counter)
for k,v in d.items():
if k in states:
result[states[k]] += Counter(v)
print(result)
Output:
defaultdict(<class 'collections.Counter'>, {'AL': Counter({'d': 26, 'a': 21, 'c': 17, 'b': 7}),
'TX': Counter({'b': 22, 'd': 18, 'a': 10, 'c': 10})})
You can just use defaultdict and count in a loop:
expected_output = defaultdict(lambda: defaultdict(int))
for postcode, state in states.items():
for key, value in d.get(postcode, {}).items():
expected_output[state][key] += value
Just as a complement of the answer of Rakesh, Here is an answer closer to your code:
res = {v:{} for v in states.values()}
for k,v in states.items():
if k in d:
sub_dict = d[k]
output_dict = res[v]
for sub_k,sub_v in sub_dict.items():
output_dict[sub_k] = output_dict.get(sub_k, 0) + sub_v
You can use something like this:
d = { 94111: {'a': 5, 'b': 7, 'd': 7},
95413: {'a': 6, 'd': 4},
84131: {'a': 5, 'b': 15, 'c': 10, 'd': 11},
73173: {'a': 15, 'c': 10, 'd': 15},
80132: {'b': 7, 'c': 7, 'd': 7} }
states = {94111: "TX", 84131: "TX", 95413: "AL", 73173: "AL", 80132: "AL"}
out = {i: 0 for i in states.values()}
for key, value in d.items():
if key in states:
if not out[states[key]]:
out[states[key]] = value
else:
for k, v in value.items():
if k in out[states[key]]:
out[states[key]][k] += v
else:
out[states[key]][k] = v
# out -> {'TX': {'a': 10, 'b': 22, 'd': 18, 'c': 10}, 'AL': {'a': 21, 'd': 26, 'c': 17, 'b': 7}}
You can use the class Counter for counting objects:
from collections import Counter
d = { 94111: {'a': 5, 'b': 7, 'd': 7},
95413: {'a': 6, 'd': 4},
84131: {'a': 5, 'b': 15, 'c': 10, 'd': 11},
73173: {'a': 15, 'c': 10, 'd': 15},
80132: {'b': 7, 'c': 7, 'd': 7} }
states = {94111: "TX", 84131: "TX", 95413: "AL", 73173: "AL", 80132: "AL"}
new_d = {}
for k, v in d.items():
if k in states:
new_d.setdefault(states[k], Counter()).update(v)
print(new_d)
# {'TX': Counter({'b': 22, 'd': 18, 'a': 10, 'c': 10}), 'AL': Counter({'d': 26, 'a': 21, 'c': 17, 'b': 7})}
You can convert new_d to the dictionary of dictionaries:
for k, v in new_d.items():
new_d[k] = dict(v)
print(new_d)
# {'TX': {'a': 10, 'b': 22, 'd': 18, 'c': 10}, 'AL': {'a': 21, 'd': 26, 'c': 17, 'b': 7}}
You can leverage dict's .items() method, which returns a list of tuples, and get the expected output in a simple one-liner:
new_dict = {value:d[key] for key, value in states.items()}
Output:
{'AL': {'b': 7, 'c': 7, 'd': 7}, 'TX': {'a': 5, 'b': 15, 'c': 10, 'd': 11}}
You might want to reconsider your choice of dict for how to store your data. If you store your data using pandas, aggregation is a lot easier.
df = pd.DataFrame(d).transpose()
df['states']=pd.Series(states)
df.groupby('states').sum()
>> a b c d
>>states
>>AL 21.0 7.0 17.0 26.0
>>TX 10.0 22.0 10.0 18.0
I have a dict looks like this :
my_dict = {
"a":[1, 2, 3],
"b":[10],
"c":[4, 5],
"d":[11]
}
And I would like to obtain a list containig all combinations keeping keys and value like this:
result = [
{"a":1, "b":10, "c":4, "d":11},
{"a":1, "b":10, "c":5, "d":11},
{"a":2, "b":10, "c":4, "d":11},
{"a":2, "b":10, "c":5, "d":11},
{"a":3, "b":10, "c":4, "d":11},
{"a":3, "b":10, "c":5, "d":11}
]
Do someone have a solution for this ?
Is there any existing solution to do this, or how should I proceed to do it myself ?
Thank you.
A task for itertools.product:
>>> from itertools import product
>>> for dict_items in product(*[product([k],v) for k, v in my_dict.items()]):
... print(dict(dict_items))
{'a': 1, 'b': 10, 'c': 4, 'd': 11}
{'a': 1, 'b': 10, 'c': 5, 'd': 11}
{'a': 2, 'b': 10, 'c': 4, 'd': 11}
{'a': 2, 'b': 10, 'c': 5, 'd': 11}
{'a': 3, 'b': 10, 'c': 4, 'd': 11}
{'a': 3, 'b': 10, 'c': 5, 'd': 11}
Small explanation:
The inner product(...) will expand the dict to a list such as [[(k1, v11), (k1, v12), ...], [(k2, v21), (k2, v22), ...], ...].
The outer product(...) will reassemble the items lists by choosing one tuple from each list.
dict(...) will create a dictionary from a sequence of (k1, v#), (k2, v#), ... tuples.
Try:
def permute(d):
k = d.keys()
perms = itertools.product(*d.values())
return [dict(zip(k, v)) for v in perms]
Example usage:
>>> d = {'a': [1, 2, 3], 'b': [10], 'c': [4, 5], 'd': [11]}
>>> pprint(permute(d))
[{'a': 1, 'b': 10, 'c': 4, 'd': 11},
{'a': 1, 'b': 10, 'c': 5, 'd': 11},
{'a': 2, 'b': 10, 'c': 4, 'd': 11},
{'a': 2, 'b': 10, 'c': 5, 'd': 11},
{'a': 3, 'b': 10, 'c': 4, 'd': 11},
{'a': 3, 'b': 10, 'c': 5, 'd': 11}]
Assuming that you are only interested in my_dict having 4 keys, it is simple enough to use nested for loops:
my_dict = {
"a": [1, 2, 3],
"b": [10],
"c": [4, 5],
"d": [11]
}
result = []
for a_val in my_dict['a']:
for b_val in my_dict['b']:
for c_val in my_dict['c']:
for d_val in my_dict['d']:
result.append({'a': a_val, 'b': b_val, 'c': c_val, 'd': d_val})
print(result)
This gives the expected result.
You can use:
from itertools import product
allNames = sorted(my_dict)
values= list(product(*(my_dict[Name] for Name in allNames)))
d = list(dict(zip(['a','b','c','d'],i)) for i in values)
Output:
[{'a': 1, 'c': 4, 'b': 10, 'd': 11},
{'a': 1, 'c': 5, 'b': 10, 'd': 11},
{'a': 2, 'c': 4, 'b': 10, 'd': 11},
{'a': 2, 'c': 5, 'b': 10, 'd': 11},
{'a': 3, 'c': 4, 'b': 10, 'd': 11},
{'a': 3, 'c': 5, 'b': 10, 'd': 11}]
itertools.product produces the combinations of a list of iterators.
dict.values() gets the list needed.
For each combination, zip up the dict.keys() with the combination.
Use a list comprehension to collect them up:
from itertools import product
from pprint import pprint
my_dict = {
"a":[1, 2, 3],
"b":[10],
"c":[4, 5],
"d":[11]
}
result = [dict(zip(my_dict,i)) for i in product(*my_dict.values())]
pprint(result)
Output:
[{'a': 1, 'b': 10, 'c': 4, 'd': 11},
{'a': 1, 'b': 10, 'c': 5, 'd': 11},
{'a': 2, 'b': 10, 'c': 4, 'd': 11},
{'a': 2, 'b': 10, 'c': 5, 'd': 11},
{'a': 3, 'b': 10, 'c': 4, 'd': 11},
{'a': 3, 'b': 10, 'c': 5, 'd': 11}]
my_dict = {'a':[1,2], 'b':[3], 'c':{'d':[4,5], 'e':[6,7]}}
I need to derive all the combinations out of it as below.
{'a':1, 'b':3, 'c':{'d':4, 'e':6}}
{'a':1, 'b':3, 'c':{'d':4, 'e':7}}
{'a':1, 'b':3, 'c':{'d':5, 'e':6}}
{'a':1, 'b':3, 'c':{'d':5, 'e':7}}
{'a':2, 'b':3, 'c':{'d':4, 'e':6}}
and so on. There could be any level of nesting here
Please let me know how to achieve this
Something that I tried is pasted below but definitely was reaching nowhere
def gen_combinations(data):
my_list =[]
if isinstance(data, dict):
for k, v in data.iteritems():
if isinstance(v, dict):
gen_combinations(v)
elif isinstance(v, list):
for i in range(len(v)):
temp_dict = data.copy()
temp_dict[k] = v[i]
print temp_dict
my_dict = {'a':[1,2], 'b':[3], 'c':{'d':[4,5], 'e':[6,7]}}
gen_combinations(my_dict)
Which resulted in
{'a': 1, 'c': {'e': [6, 7], 'd': [4, 5]}, 'b': [3]}
{'a': 2, 'c': {'e': [6, 7], 'd': [4, 5]}, 'b': [3]}
{'e': 6, 'd': [4, 5]}
{'e': 7, 'd': [4, 5]}
{'e': [6, 7], 'd': 4}
{'e': [6, 7], 'd': 5}
{'a': [1, 2], 'c': {'e': [6, 7], 'd': [4, 5]}, 'b': 3}
from itertools import product
my_dict = {'a':[1,2], 'b':[3], 'c':{'d':[4,5], 'e':[6,7]}}
def process(d):
to_product = [] # [[('a', 1), ('a', 2)], [('b', 3),], ...]
for k, v in d.items():
if isinstance(v, list):
to_product.append([(k, i) for i in v])
elif isinstance(v, dict):
to_product.append([(k, i) for i in process(v)])
else:
to_product.append([(k, v)])
return [dict(l) for l in product(*to_product)]
for i in process(my_dict):
print(i)
Output:
{'a': 1, 'b': 3, 'c': {'e': 6, 'd': 4}}
{'a': 2, 'b': 3, 'c': {'e': 6, 'd': 4}}
{'a': 1, 'b': 3, 'c': {'e': 6, 'd': 5}}
{'a': 2, 'b': 3, 'c': {'e': 6, 'd': 5}}
{'a': 1, 'b': 3, 'c': {'e': 7, 'd': 4}}
{'a': 2, 'b': 3, 'c': {'e': 7, 'd': 4}}
{'a': 1, 'b': 3, 'c': {'e': 7, 'd': 5}}
{'a': 2, 'b': 3, 'c': {'e': 7, 'd': 5}}
Upd:
Code that works as asked here:
from itertools import product
my_dict = {'a':[1,2], 'e':[7], 'f':{'x':[{'a':[3,5]}, {'a':[4]}] } }
def process(d):
to_product = [] # [[('a', 1), ('a', 2)], [('b', 3),], ...]
for k, v in d.items():
if isinstance(v, list) and all(isinstance(i, dict) for i in v):
# specific case, when list of dicts process differently...
c = product(*list(process(i) for i in v))
to_product.append([(k, list(l)) for l in c])
elif isinstance(v, list):
to_product.append([(k, i) for i in v])
elif isinstance(v, dict):
to_product.append([(k, i) for i in process(v)])
else:
to_product.append([(k, v)])
return [dict(l) for l in product(*to_product)]
for i in process(my_dict):
print(i)
Output:
{'f': {'x': [{'a': 3}, {'a': 4}]}, 'a': 1, 'e': 7}
{'f': {'x': [{'a': 3}, {'a': 4}]}, 'a': 2, 'e': 7}
{'f': {'x': [{'a': 5}, {'a': 4}]}, 'a': 1, 'e': 7}
{'f': {'x': [{'a': 5}, {'a': 4}]}, 'a': 2, 'e': 7}
Solve it with two steps.
First replace each dict with a list of dicts generated by gen_combinations, called recursively.
Second, make the inner join between all keys. Each key has a flat list now.