I have a list of dictionaries
ld = [{'a': 1}, {'b': 2, 'c': 3}, {'d': 4, 'e': 5}]
I need to get all the elements with the longest length from my list, i.e.
{'b': 2, 'c': 3} and {'d': 4, 'e': 5}.
I'm not very knowledgeable in Python but I found that:
>>> max(ld, key=len)
{'b': 2, 'c': 3}
And, an even better solution that returns the index of the longest length dictionary:
>>> max(enumerate(ld), key=lambda tup: len(tup[1]))
(1, {'b': 2, 'c': 3})
I would like to use an expression that would return something like
(1: {'b': 2, 'c': 3}, 2: {'d': 4, 'e': 5})
and I feel like I'm not far from the solution (or maybe I am) but I just don't know how to get it.
You can find the length of the maximum dictionary in the structure, and then use a list comprehension:
ld = [{'a':1}, {'b':2, 'c':3}, {'d':4, 'e':5}]
_max = max(map(len, ld))
new_result = dict(i for i in enumerate(ld) if len(i[-1]) == _max)
Output:
{1: {'b': 2, 'c': 3}, 2: {'d': 4, 'e': 5}}
Ajax1234 provided a really good solution. If you want something of a beginner level, here's a solution.
ld = [{'a':1}, {'b':2, 'c':3}, {'d':4, 'e':5}]
ans = dict()
for value in ld:
if len(value) in ans:
ans[len(value)].append(value)
else:
ans[len(value)] = list()
ans[len(value)].append(value)
ans[max(ans)]
Basically, you add everything in a dictionary to get the maximum dictionary size to be the key, and dictionary list to be the value, and then get that maximum size list of dictionaries.
There are a number of ways you could do this in python. Here's one example which illustrates a few different python capabilities:
ld = [{'a':1}, {'b':2, 'c':3}, {'d':4, 'e':5}]
lengths = list(map(len, ld)) # [1, 2, 2]
max_len = max(lengths) # 2
index_to_max_length_dictionaries = {
index: dictionary
for index, dictionary in enumerate(ld)
if len(dictionary) == max_len
}
# output: {1: {'b': 2, 'c': 3}, 2: {'d': 4, 'e': 5}}
Find the maximum length and then use a dictionary comprehension to find the dictionaries with such length
max_l = len(max(ld, key=len))
result = {i: d for i, d in enumerate(ld) if len(d) == max_l}
This is the simplest and more readable approach you can take
Below is another path, a better (but more verbose) approach
max_length = 0
result = dict()
for i, d in enumerate(ld):
l = len(d)
if l == max_length:
result[i] = d
elif l > max_length:
max_length = l
result = {i: d}
This is the most efficient approach. It just iterate 1 time through the full input list
I have three dictionaries (or more):
A = {'a':1,'b':2,'c':3,'d':4,'e':5}
B = {'b':1,'c':2,'d':3,'e':4,'f':5}
C = {'c':1,'d':2,'e':3,'f':4,'g':5}
How can I get a dictionary of the average values of every key in the three dictionaries?
For example, given the above dictionaries, the output would be:
{'a':1/1, 'b':(2+1)/2, 'c':(3+2+1)/3, 'd':(4+3+2)/3, 'e':(5+4+3)/3, 'f':(5+4)/2, 'g':5/1}
You can use Pandas, like this:
import pandas as pd
df = pd.DataFrame([A,B,C])
answer = dict(df.mean())
print(answer)
I use Counter to solve this problem. Please try the following code :)
from collections import Counter
A = {'a':1,'b':2,'c':3,'d':4,'e':5}
B = {'b':1,'c':2,'d':3,'e':4,'f':5}
C = {'c':1,'d':2,'e':3,'f':4,'g':5}
sums = Counter()
counters = Counter()
for itemset in [A, B, C]:
sums.update(itemset)
counters.update(itemset.keys())
ret = {x: float(sums[x])/counters[x] for x in sums.keys()}
print ret
The easiest way would be to use collections.Counter as explained here, like this:
from collections import Counter
sums = dict(Counter(A) + Counter(B) + Counter(C))
# Which is {'a': 1, 'c': 6, 'b': 3, 'e': 12, 'd': 9, 'g': 5, 'f': 9}
means = {k: sums[k] / float((k in A) + (k in B) + (k in C)) for k in sums}
The result would be:
>>> means
{'a': 1.0, 'b': 1.5, 'c': 2.0, 'd': 3.0, 'e': 4.0, 'f': 4.5, 'g': 5.0}
If you are working in python 2.7 or 3.5 you can use the following:
keys = set(A.keys()+B.keys()+C.keys())
D = {key:(A.get(key,0)+B.get(key,0)+C.get(key,0))/float((key in A)+(key in B)+(key in C)) for key in keys}
which outputs
D
{'a': 1.0, 'c': 2.0, 'b': 1.5, 'e': 4.0, 'd': 3.0, 'g': 5.0, 'f': 4.5}
if you don't want to use any packages. This doesn't work in python 2.6 and below though.
Here's a very general way to do so (i.e. you can easily change to any aggregation function).:
def aggregate_dicts(dicts, operation=lambda x: sum(x) / len(x)):
"""
Aggregate a sequence of dictionaries to a single dictionary using `operation`. `Operation` should
reduce a list of all values with the same key. Keyrs that are not found in one dictionary will
be mapped to `None`, `operation` can then chose how to deal with those.
"""
all_keys = set().union(*[el.keys() for el in dicts])
return {k: operation([dic.get(k, None) for dic in dicts]) for k in all_keys}
example:
dicts_diff_keys = [{'x': 0, 'y': 1}, {'x': 1, 'y': 2}, {'x': 2, 'y': 3, 'c': 4}]
def mean_no_none(l):
l_no_none = [el for el in l if el is not None]
return sum(l_no_none) / len(l_no_none)
aggregate_dicts(dicts_diff_keys, operation= mean_no_none)
#{'x': 1.0, 'c': 4.0, 'y': 2.0}
This question already has answers here:
How to merge dicts, collecting values from matching keys?
(17 answers)
Closed 5 months ago.
I'm trying to merge three dictionaries, which all have the same keys, and either lists of values, or single values.
one={'a': [1, 2], 'c': [5, 6], 'b': [3, 4]}
two={'a': [2.4, 3.4], 'c': [5.6, 7.6], 'b': [3.5, 4.5]}
three={'a': 1.2, 'c': 3.4, 'b': 2.3}
What I need is for all the items in the values to be added to one list.
result={'a': [1, 2, 2.4, 3.4, 1.2], 'c': [5, 6, 5.6, 7.6, 2.3], 'b': [3, 4, 3.5, 4.5, 3.4]}
I have tried several things, but most put the values into nested lists.
E.g.
out=dict((k, [one[k], two.get(k), three.get(k)]) for k in one)
{'a': [[1, 2], [2.4, 3.4], 1.2], 'c': [[5, 6], [5.6, 7.6], 3.4], 'b': [[3, 4], [3.5, 4.5], 2.3]}
I tried updating it by looping through the values:
out.update((k, [x for x in v]) for k,v in out.iteritems())
but the results was exactly the same.
I have tried to simply add the lists, but because the third dictionary has only a float, I couldn't do it.
check=dict((k, [one[k]+two[k]+three[k]]) for k in one)
So I tried to first add the lists in values of one and two, and then append the value of three. Adding the lists worked well, but then when I tried to append the float from the third dictionary, suddenly the whole value went to 'None'
check=dict((k, [one[k]+two[k]]) for k in one)
{'a': [[1, 2, 2.4, 3.4]], 'c': [[5, 6, 5.6, 7.6]], 'b': [[3, 4, 3.5, 4.5]]}
new=dict((k, v.append(three[k])) for k,v in check.items())
{'a': None, 'c': None, 'b': None}
As a one-liner, with a dictionary comprehension:
new = {key: value + two[key] + [three[key]] for key, value in one.iteritems()}
This creates new lists, concatenating the list from one with the corresponding list from two, putting the single value in three into a temporary list to make concatenating easier.
Or with a for loop updating one in-place:
for key, value in one.iteritems():
value.extend(two[key])
value.append(three[key])
This uses list.extend() to update original list in-place with the list from two, and list.append() to add the single value from three.
Where you went wrong:
your first attempt creates a new list with the values from one, two and three nested within rather than concatenating the existing lists. Your attempt to clean that up just copied those nested lists across.
Your second attempt didn't work because the value in three is not a list so could not be concatenated. I created a new list just for that one value.
Your last attempt should not have used list.append() in a generator expression, because you store the return value of that method, which is always None (its change is stored in v directly and the list doesn't need returning again).
Demo of the first approach:
>>> one={'a': [1, 2], 'c': [5, 6], 'b': [3, 4]}
>>> two={'a': [2.4, 3.4], 'c': [5.6, 7.6], 'b': [3.5, 4.5]}
>>> three={'a': 1.2, 'c': 3.4, 'b': 2.3}
>>> {key: value + two[key] + [three[key]] for key, value in one.iteritems()}
{'a': [1, 2, 2.4, 3.4, 1.2], 'c': [5, 6, 5.6, 7.6, 3.4], 'b': [3, 4, 3.5, 4.5, 2.3]}
Arbitrary dictionary number and keys
The issues with your attempt are covered by #MartijnPieters' solution.
For a generalised solution, consider using itertools.chain to chain multiple dictionaries. You can also use a defaultdict for the more general case where you do not find the same keys in each dictionary.
from collections import defaultdict
from itertools import chain
from operator import methodcaller
# dictionaries with non-equal keys, values all lists for simplicity
one = {'a': [1, 2], 'c': [5, 6], 'b': [3, 4], 'e': [6.2]}
two = {'a': [2.4, 3.4], 'c': [5.6, 7.6], 'b': [3.5, 4.5], 'f': [1.3]}
three = {'a': [1.2], 'c': [3.4], 'b': [2.3], 'e': [3.1]}
# initialise defaultdict of lists
dd = defaultdict(list)
# iterate dictionary items
dict_items = map(methodcaller('items'), (one, two, three))
for k, v in chain.from_iterable(dict_items):
dd[k].extend(v)
print(dd)
# defaultdict(list,
# {'a': [1, 2, 2.4, 3.4, 1.2],
# 'b': [3, 4, 3.5, 4.5, 2.3],
# 'c': [5, 6, 5.6, 7.6, 3.4],
# 'e': [6.2, 3.1],
# 'f': [1.3]})
Note defaultdict is a subclass of dict so there's generally no need to convert the result to a regular dict.
A robust solution. =)
def FullMergeDict(D1, D2):
for key, value in D1.items():
if key in D2:
if type(value) is dict:
FullMergeDict(D1[key], D2[key])
else:
if type(value) in (int, float, str):
D1[key] = [value]
if type(D2[key]) is list:
D1[key].extend(D2[key])
else:
D1[key].append(D2[key])
for key, value in D2.items():
if key not in D1:
D1[key] = value
if __name__ == '__main__':
X = {
'a': 'aaa',
'c': [1,3,5,7],
'd': 100,
'e': {'k': 1, 'p': 'aa','t': [-1,-2]},
'f': {'j':1}
}
Y = {
'b': 'bbb',
'd': 200,
'e': {'k': 2, 'p': 'bb','o': [-4]},
'c': [2,4,6],
'g': {'v':2}
}
FullMergeDict(X, Y)
exit(0)
Result:
X = {
'a': 'aaa',
'b': 'bbb',
'c': [1, 3, 5, 7, 2, 4, 6],
'd': [100, 200],
'e': {'k': [1, 2], 'o': [-4], 'p': ['aa', 'bb'], 't': [-1, -2]},
'f': {'j': 1},
'g': {'v': 2}}
If you have different keys and different types of values in dictionaries you can use the following approach:
from collections import defaultdict, Iterable
dct1 = {'a': [1, 2]}
dct2 = {'a': [3], 'b': [5, 6]}
dct3 = {'a': 4, 'c': 7}
result = defaultdict(list)
for dct in [dct1, dct2, dct3]:
for k, v in dct.items():
if isinstance(v, Iterable):
result[k].extend(v)
else:
result[k].append(v)
print(result)
# defaultdict(<class 'list'>, {'a': [1, 2, 3, 4], 'b': [5, 6], 'c': [7]})
One line solution (also handles for keys present in only one dict):
{ key:one.get(key,[])+two.get(key,[]) for key in set(list(one.keys())+list(two.keys())) }
Example 1:
one = {'a': [1, 2], 'c': [5, 6], 'b': [3, 4]}
two = {'a': [2.4, 3.4], 'c': [5.6, 7.6], 'd': [3.5, 4.5]}
{ key:one.get(key,[])+two.get(key,[]) for key in set(list(one.keys())+list(two.keys())) }
Output:
{'a': [1, 2, 2.4, 3.4], 'b': [3, 4], 'c': [5, 6, 5.6, 7.6], 'd': [3.5,
4.5]}
Example 2:
x={1:['a','b','c']}
y={1:['d','e','f'],2:['g']}
{ key:x.get(key,[])+y.get(key,[]) for key in set(list(x.keys())+list(y.keys())) }
Output:
{1: ['a', 'b', 'c', 'd', 'e', 'f'], 2: ['g']}
See this help or not:
>>> dic={}
>>> k=[]
>>> for i in 'abc':
k=one[i]+two[i]
k.append(three[i])
dic[i]=k
>>> dic
{'c': [5, 6, 5.6, 7.6, 3.4], 'a': [1, 2, 2.4, 3.4, 1.2], 'b': [3, 4, 3.5, 4.5, 2.3]}
I have a dictionary associating a probability to a char
d = {'a': 0.2, 'b': 0.3, 'c': 0.4, 'd':0.1}
And I am searching a way to associate to each char the lowest value of his frequency distribution. So every char must be associated to the sum of the previous ones.
I know dictionary are not ordered but it should return something like
ddist = {'a': 0, 'b': 0.2, 'c': 0.5, 'd': 0.9}
I tried with a loop but I did not find a way to get the previous values...
Any ideas ?
You can simply iterate over a sorted version of the keys:
d = {'a': 0.2, 'b': 0.3, 'c': 0.4, 'd':0.1}
ddist = {}
t = 0
for key in sorted(d):
ddist[key] = t
t += d[key]
As dicts are unordered, so you need to define the key order yourself, or use collections.OrderedDict from the start.
>>> def accumulate(seq):
total = 0
for item in seq:
yield total
total += item
...
>>> keys = ['a', 'b', 'c', 'd'] #For your dict, this is sorted(d)
>>> dict(zip(keys, accumulate(d[k] for k in keys)))
{'a': 0, 'c': 0.5, 'b': 0.2, 'd': 0.9}
#or
>>> from collections import OrderedDict
>>> OrderedDict(zip(keys, accumulate(d[k] for k in keys)))
OrderedDict([('a', 0), ('b', 0.2), ('c', 0.5), ('d', 0.9)])
So I want to try and merge only certain keys from one dictionary to another so doing
a = {'a':2, 'b':3, 'c':5}
b = {'d':2, 'e':4}
a.update(b)
>>> a
{'a': 2, 'c': 5, 'b': 3, 'e': 4, 'd': 2} # returns a merge of all keys
However say you only wanted the key and value pair 'd':2 and not all of the elements within the dictionary how would this be possible so you get:
{'a': 2, 'c': 5, 'b': 3, 'd': 2}
If you know you want to update a with b['d'], use this:
a['d'] = b['d']
I don't know if I got what you're asking. Anyway, if you want to update just some keys on a dictionary with keys from another, you can do:
a['d'] = b['d']
or, if you want to update multiple keys:
for to_update in keys_to_update: # keys_to_update is a list
a[to_update] = b[to_update]
You may use following snippet:
a = {'a':2, 'b':3, 'c':5}
b = {'d':2, 'e':4}
desiredKeys = ('d',)
for key, val in b.items():
if key in desiredKeys:
a[key] = b[key]
print( a )
Sample above will output:
{'d': 2, 'b': 3, 'c': 5, 'a': 2}