Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 7 years ago.
Improve this question
I have around 1000 of dictionary like this.
x = {'a':1, 'b': 2, 'c':5}
y = {'b':10, 'c': 11}
z = {'e':5, 'b': 2}
I want a merged dictionary like this.
f = {'a':[1,0,0], 'b': [2,10,2], 'c':[5,11,0], 'e':[0,0,5]}
Is there a iterative way to do this.? After creating the final dictionary i want to create a matrix where a , b, c, e will be the column heading with three rows as shown below:
a b c e
1 2 5 0
0 10 11 0
0 2 0 5
keys = ('a', 'b', 'c', 'e')
dicts = (x, y, z)
f = {k: [d.get(k, 0) for d in dicts] for k in keys}
Or as a one-liner:
f = {k: [d.get(k, 0) for d in (x, y, z)] for k in ('a', 'b', 'c', 'e')}
You can get your keys with dict.viewkeys and a reduce function, then use collections.defaultdict to append the corresponding values to keys :
>>> x = {'a':1, 'b': 2, 'c':5}
>>> y = {'b':10, 'c': 11}
>>> z = {'e':5, 'b': 2}
>>> l=[x,y,z]
>>> keys=reduce(lambda i,j: i | j ,[j.viewkeys() for j in l])
>>> from collections import defaultdict
>>> d=defaultdict(list)
>>> for k in keys :
... for i in l:
... d[k].append(i.get(k,0))
...
>>> d
defaultdict(<type 'list'>, {'a': [1, 0, 0], 'c': [5, 11, 0], 'b': [2, 10, 2], 'e': [0, 0, 5]})
Then you can create the proper matrix :
>>> [[i]+j for i,j in d.items()]
[['a', 1, 0, 0], ['c', 5, 11, 0], ['b', 2, 10, 2], ['e', 0, 0, 5]]
Here's how to perform the two tasks:
from collections import defaultdict
dicts = [{'a':1, 'b': 2, 'c':5},
{'b':10, 'c': 11},
{'e':5, 'b': 2}]
# determine what keys exist in the dictionaries and sort them
keys = sorted(reduce(lambda a,b: a|b, (set(d) for d in dicts)))
f = defaultdict(list)
for k in keys:
for d in dicts:
f[k].append(d.get(k, 0))
print 'merged\n f: {}'.format(dict(f))
matrix = [keys] + [[d.get(k, 0) for k in keys] for d in dicts]
print '\nmatrix:'
for row in matrix:
print ' '.join('{:>2}'.format(elem) for elem in row)
Output:
merged
f: {'a': [1, 0, 0], 'c': [5, 11, 0], 'b': [2, 10, 2], 'e': [0, 0, 5]}
matrix:
a b c e
1 2 5 0
0 10 11 0
0 2 0 5
Related
Suppose that the range of parameters of interest are given a dictionary that contains the range for each parameter of interest:
G = {'a': [1,2], 'b': [3], 'c': [1, 2.5] }
The goal is to extract every parameter configuration on this grid. In the example above, there are 4 such, corresponding to 2 values of a, and two values of b:
G1 = {'a': 1, 'b': 3, 'c': 1 }
G2 = {'a': 2, 'b': 3, 'c': 1 }
G3 = {'a': 1, 'b': 3, 'c': 2.5 }
G4 = {'a': 2, 'b': 3, 'c': 2.5 }
It's straightforward to write two nested for loops to produce all such configurations, it becomes less trivial how to do it for a general case, when there are a variable number of lists in G.
The only solution that comes to my mind is to create a multi-index vector vec=[0,0] which is as long as the number of parameters, and increment to iterate over all possible configurations: [0,0] -> [1,0] -> [0,1] -> [1,1]:
G = {'a': [1,2], 'b': [3], 'c': [1, 2.5] }
def get_configs(G):
keys = list(G.keys())
lists = list(G.values())
sizes = [len(l) for l in lists]
num_confs = np.prod(sizes)
index = [0]*(len(G)+1)
configs = []
while len(configs)<num_confs:
configs.append( {keys[i]: lists[i][index[i]] for i in range(len(G))})
index[0] += 1
cur = 0
while len(configs)<num_confs and index[cur]>=sizes[cur]:
index[cur]=0
cur += 1
index[cur] += 1
return configs
configs = get_configs(G)
print(configs)
However, the solution seems a bit over-complicated and ugly. Is there a clean solution using python?
Here is a generalizable implementation using itertools.product:
from itertools import product
def dict_configs(d):
for vcomb in product(*d.values()):
yield dict(zip(d.keys(), vcomb))
Usage:
>>> G = {'a': [1,2], 'b': [3], 'c': [1, 2.5] }
>>> for config in dict_configs(G):
... print(config)
...
{'a': 1, 'b': 3, 'c': 1}
{'a': 1, 'b': 3, 'c': 2.5}
{'a': 2, 'b': 3, 'c': 1}
{'a': 2, 'b': 3, 'c': 2.5}
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}
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
Could you explain how to assign certain scores from a list to values in multiple lists and get the total score for each value?
score = [1,2,3,4,5] assigne a score based on the position in the list
l_1 = [a,b,c,d,e]
assign a=1, b=2, c=3, d=4, e=5
l_2 = [c,a,d,e,b]
assign c=1, a=2, d=3, e=4, b=5
I am trying to get the result like
{'e':9, 'b': 7, 'd':7, 'c': 4, 'a': 3}
Thank you!
You can zip the values of score to each list, which gives you a tuple of (key, value) for each letter-score combination. Make each zipped object a dict. Then use a dict comprehension to add the values for each key together.
d_1 = dict(zip(l_1, score))
d_2 = dict(zip(l_2, score))
{k: v + d_2[k] for k, v in d_1.items()}
# {'a': 3, 'b': 7, 'c': 4, 'd': 7, 'e': 9}
You better use zip function:
dic = {'a':0, 'b': 0, 'c':0, 'd': 0, 'e': 0}
def score(dic, *args):
for lst in args:
for k, v in zip(lst, range(len(lst))):
dic[k] += v+1
return dic
l_1 = ['a','b','c','d','e']
l_2 = ['c','a','d','e','b']
score(dic, l_1, l_2)
Instead of storing your lists in separate variables, you should put them in a list of lists so that you can iterate through it and calculate the sums of the scores according to each key's indices in the sub-lists:
score = [1, 2, 3, 4, 5]
lists = [
['a','b','c','d','e'],
['c','a','d','e','b']
]
d = {}
for l in lists:
for i, k in enumerate(l):
d[k] = d.get(k, 0) + score[i]
d would become:
{'a': 3, 'b': 7, 'c': 4, 'd': 7, 'e': 9}
from collections import defaultdict
score = [1,2,3,4,5] # note: 0 no need to use this list if there is no scenario like [5,6,9,10,4]
l_1 = ['a','b','c','d','e']
l_2 = ['c','a','d','e','b']
score_dict = defaultdict(int)
'''
for note: 0
if your score is always consecutive
like score = [2,3,4,5,6] or [5,6,7,8,9]...
you don't need to have seperate list of score you can set
start = score_of_char_at_first_position_ie_at_zero-th_index
like start = 2, or start = 5
else use this function
def add2ScoreDict( lst):
for pos_score, char in zip(score,lst):
score_dict[char] += pos_score
'''
def add2ScoreDict( lst):
for pos, char in enumerate( lst,start =1):
score_dict[char] += pos
# note: 1
add2ScoreDict( l_1)
add2ScoreDict( l_2)
#print(score_dict) # defaultdict(<class 'int'>, {'a': 3, 'b': 7, 'c': 4, 'd': 7, 'e': 9})
score_dict = dict(sorted(score_dict.items(), reverse = True, key=lambda x: x[1]))
print(score_dict) # {'e': 9, 'b': 7, 'd': 7, 'c': 4, 'a': 3}
edit 1:
if you have multiple lists put them in list_of_list = [l_1, l_2] so that you don't have to call func add2ScoreDict yourself again and again.
# for note: 1
for lst in list_of_list:
add2ScoreDict( lst)
You could zip both lists with score as one list l3 then you could use dictionary comprehension with filterto construct your dicitonary. The key being index 1 of the the newly formed tuples in l3, and the value being the sum of all index 0's in l3 after creating a sublist that is filtered for only matching index 0's
score = [1,2,3,4,5]
l_1 = ['a', 'b', 'c', 'd', 'e']
l_2 = ['c', 'a', 'd', 'e', 'b']
l3 = [*zip(score, l_1), *zip(score,l_2)]
d = {i[1]: sum([j[0] for j in list(filter(lambda x: x[1] ==i[1], l3))]) for i in l3}
{'a': 3, 'b': 7, 'c': 4, 'd': 7, 'e': 9}
Expanded Explanation:
d = {}
for i in l3:
f = list(filter(lambda x: x[1] == i[1], l3))
vals = []
for j in f:
vals.append(j[0])
total_vals = sum(vals)
d[i[1]] = total_vals
The simplest way is probably to use a Counter from the Python standard library.
from collections import Counter
tally = Counter()
scores = [1, 2, 3, 4, 5]
def add_scores(letters):
for letter, score in zip(letters, scores):
tally[letter] += score
L1 = ['a', 'b', 'c', 'd', 'e']
add_scores(L1)
L2 = ['c', 'a', 'd', 'e', 'b']
add_scores(L2)
print(tally)
>>> python tally.py
Counter({'e': 9, 'b': 7, 'd': 7, 'c': 4, 'a': 3})
zip is used to pair letters and scores, a for loop to iterate over them and a Counter to collect the results. A Counter is actually a dictionary, so you can write things like
tally['a']
to get the score for letter a or
for letter, score in tally.items():
print('Letter %s scored %s' % (letter, score))
to print the results, just as you would with a normal dictionary.
Finally, small ells and letter O's can be troublesome as variable names because they are hard to distinguish from ones and zeros. The Python style guide (often referred to as PEP8) recommends avoiding them.
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