Merge an arbitrary number of dictionaries of lists - python

How could dictionaries whose values are lists be merged in Python, so that all of the keys are moved into one dictionary, and all the elements of each list moved into a single list for each key?
For example, with these dictionaries:
x = {'a': [2], 'b': [2]}
y = {'b': [11], 'c': [11]}
... the result of the merging should be like this:
{'a': [2], 'b': [2, 11], 'c': [11]}
How could this be done with any number of dictionaries, not just two?

for k, v in y.items():
x.setdefault(k, []).extend(v)

You can use following approach, which uses sets and dict comprehension
x = {'a': [2], 'b': [2]}
y = {'b': [11], 'c': [11]}
all_keys = set(x) | set(y)
print {k:x.get(k, [])+y.get(k, []) for k in all_keys}
Results:
{'a': [2], 'c': [11], 'b': [2, 11]}

To collect all the lists together, form a result dictionary that maps your keys to lists. The simplest way to do this is with dict.setdefault() followed by a call to list.extend to grow the lists:
r = {}
for d in [x, y]:
for k, v in d.items():
r.setdefault(k, []).extend(v)
A little more elegant way is with collections.defaultdict() where the automatic default is a new empty list:
from collections import defaultdict
r = defaultdict(list)
for d in [x, y]:
for k, v in d.items():
r[k].extend(v)

Here's a solution that works for an arbitrary number of dictionaries:
def collect(*dicts):
result = {}
for key in set.union(*(set(d) for d in dicts)):
result[key] = sum((d.get(key, []) for d in dicts), [])
return result
It's essentially a generalisation of Tanveer's answer, taking advantage of the fact that set.union() can accept any number of dictionaries as arguments.
Here's an example of the function in use:
>>> x = {'a': [2], 'b': [2]}
>>> y = {'b': [11], 'c': [11]}
>>> collect(x, y)
{'a': [2], 'c': [11], 'b': [2, 11]}
... and with multiple dictionaries:
>>> z = {'c': [12, 13], 'd': [5]}
>>> collect(x, y, z)
{'a': [2], 'c': [11, 12, 13], 'b': [2, 11], 'd': [5]}

x = {'a': [2], 'b': [2]}
y = {'b': [11], 'c': [11]}
result = {}
for key,value in x.iteritems():
result[key] = value
for key,value in y.iteritems():
if key in result:
for l in value:
result[key].append(l)
else:
result[key] = value
print result

Related

How to compare the elements of a list of dictionary by its value and extract matched keys in Python?

I have a list of dictionaries and need to group keys by comparing values of elements in order to get the list of keys with close values.
l = [{'a': [6], 'b': [7, 16], 'c': [13], 'd': [32]}, {'a': [9], 'b': [43], 'c': [44], 'd': [45, 52], 'e': [47], 'f': [48], 'g': [54]}]
Example of output:
l2 = [['a_b', 'b', 'c', 'd'], ['a', 'b_c_d_e_f', 'd_g']]
The difference between the values is 3 maximum.
The general idea here is to create a list of "buckets", sort them by value, and then iteratively combine adjacent buckets that are close enough.
from typing import Dict, List, Tuple
def make_buckets(d: Dict[str, List[int]]) -> List[str]:
buckets = sorted(
[([k], [i]) for k, v in d.items() for i in v],
key=lambda b: b[1][0]
)
Bucket = Tuple[List[str], List[int]]
def merge(a: Bucket, b: Bucket) -> bool:
if min(b[1]) - max(a[1]) > 2:
return False
a[0][:] = sorted(a[0] + b[0])
a[1][:] = sorted(a[1] + b[1])
buckets.remove(b)
return True
while True:
for a, b in zip(buckets, buckets[1:]):
if merge(a, b):
break
else:
break
return sorted("_".join(k) for k, _ in buckets)
dicts = [
{'a': [6], 'b': [7, 16], 'c': [13], 'd': [32]},
{'a': [9], 'b': [43], 'c': [44], 'd': [45, 52], 'e': [47], 'f': [48], 'g': [54]}
]
print([make_buckets(d) for d in dicts])
prints:
[['a_b', 'b', 'c', 'd'], ['a', 'b_c_d_e_f', 'd_g']]

Given key value pairs, sort output alphabetically and increment values

dict1 = {'a': 10, 'b': 8, 'c':5}
dict2 = {'d': 6, 'c': 4, 'a':20}
Given two dictionaries, I'd like an output of.
output = {'a':30, 'b':8, 'c':9, 'd':6}
This is what I've so far, not quite sure what I'd do next.
I'm looking for a solution that is efficient in time/space complexity.
def merge_dict(dict1, dict2):
merged_dictionaries = {**dict1, **dict2}
return merged_dictionaries
dict1 = {'a': 10, 'b': 8, 'c':5}
dict2 = {'d': 6, 'c': 4, 'a':20}
merge_dictionaries = merge_dict (dict1, dict2)
sorted_dictionary = sorted(merge_dictionaries)
If the values are numeric, you can use counters:
from collections import Counter
def merge_dicts(*dicts):
return dict(sum(map(Counter, dicts), Counter()))
dict1 = merge_dicts(dict1, dict2)
dict1
# {'a': 30, 'b': 8, 'c': 9, 'd': 6}
This might be a bit excessive for only two dictionaries, so another option is:
for k, v in dict2.items():
dict1[k] = dict1.setdefault(k, 0) + v
dict1
# {'a': 30, 'b': 8, 'c': 9, 'd': 6}
Which updates dict1 in-place.
Finally, if you really need the result sorted (python3.7+), use
result = {k : dict1[k] for k in sorted(dict1)}
You can use a dict comprehension that iterates over a sorted union of the keys of the two dicts, and outputs values that are sums of the respective values of two dicts by the given keys, defaulting to 0:
{k: dict1.get(k, 0) + dict2.get(k, 0) for k in sorted(dict1.keys() | dict2.keys())}
This returns:
{'a': 30, 'b': 8, 'c': 9, 'd': 6}
result = dict(Counter(dict1) + Counter(dict2))
result = {k: result[k] for k in sorted(result)}
First merge the dicts together by turning them into Counters and convert the result it back into a dict, then sort the dict by keys.
You can Try Collections for add two dictionary..
from collections import Counter
def merged_dic():
dict1 = {'a': 10, 'b': 8, 'c':5}
dict2 = {'d': 6, 'c': 4, 'a':20}
a = Counter(dict1)
b = Counter(dict2)
c = a+b
print(dict(c))
merged_dic()
Output:- {'a': 30, 'b': 8, 'c': 9, 'd': 6}

How can i add the terms of one dict to another?

Let's assume i start with this dictionary:
mydict = {
'a': [[2,4], [5,6]],
'b': [[1,1], [1,7,9], [6,2,3]],
'c': [['a'], [4,5]],
}
How can i append values to 'a' yet be able to add a new key if i needed to let's say 'd' what i tried is
plus_min_dict = {}
plus_min_dict[key] = reference_dataset[key][line_number]
but it only gave one value per key apparently = destroyed the previous value, i want to update or append yet still be able to create a new key if it doesn't exist
Edit: To clarify let's assume this is my initial dictionary:
mydict = {
'a': [[2,4]],}
i do other calculations with another dictionary let's assume it's :
second_dict = {
'a': [ [5,6]],
'b': [[1,1], [1,7,9]],
'c': [['a'], [4,5]],
}
these calculations showed me that i have interest in [5,6] of 'a' and [1,7,9] of 'b' so i want mydict to become:
mydict = {
'a': [[2,4], [5,6]],
'b': [[1,7,9]],
}
If I understand well your question, you want to append a new value to your dictionary if the key already exists. If so, I would use a defaultdict for a simple reason. With a defaultdict you can use the method += to create (if does not exist) or add (if exist) an element :
from collections import defaultdict
# Your dictionaries
mydict = {
'a': [[2,4], [5,6]],
'b': [[1,1], [1,7,9], [6,2,3]],
'c': [['a'], [4,5]],
}
plus_min_dict = {'a': [[3,3]]}
# d is a DefaultDict containing mydict values
d=defaultdict(list,mydict)
# d_new is a DefaultDict containing plus_min_dict dict
d_new = defaultdict(list, plus_min_dict)
# Add all key,values of d in d_new
for k, v in d.items():
d_new[k] += d[k]
print(d_new)
Results :
defaultdict(<class 'list'>, {'c': [['a'], [4, 5]], 'a': [[3, 3], [2, 4], [5, 6]], 'b': [[1, 1], [1, 7, 9], [6, 2, 3]]})
Use an if else loop
mydict = {'a': [[2,4]],}
second_dict = {
'a': [ [5,6]],
'b': [[1,1], [1,7,9]],
'c': [['a'], [4,5]]}
missing_values = {
'a': [5,6],
'b': [1,7,9]}
for key, value in missing_values.items():
if key in mydict:
mydict[key ].append(value)
else:
mydict[key ] = [value]
print(mydict)
Result:
{'a': [[2, 4], [5, 6]], 'b': [[1, 7, 9]]}
To append an item into 'a', you can do this:
mydict['a'] += ['test_item']
Or:
mydict['a'].append('test_item')
You can just append:
mydict = {
'a': [[2,4], [5,6]],
'b': [[1,1], [1,7,9], [6,2,3]],
'c': [['a'], [4,5]],
}
mydict['a'].append([7,8])
mydict['d'] = [0,1]
print(mydict)

Dictionary of lists from list of lists

I have a list of lists of data:
[[1422029700000, 230.84, 230.42, 230.31, 230.32, 378], [1422029800000, 231.84, 231.42, 231.31, 231.32, 379], ...]
and a list of keys:
['a', 'b', 'c', 'd', 'e']
I want to combine them to a dictionary of lists so it looks like:
['a': [1422029700000, 1422029800000], 'b': [230.84, 231.84], ...]
I can do this using loops but I am looking for a pythonic way.
It is quite simple:
In [1]: keys = ['a','b','c']
In [2]: values = [[1,2,3],[4,5,6],[7,8,9]]
In [7]: dict(zip(keys, zip(*values)))
Out[7]: {'a': (1, 4, 7), 'b': (2, 5, 8), 'c': (3, 6, 9)}
If you need lists as values:
In [8]: dict(zip(keys, [list(t) for t in zip(*values)]))
Out[8]: {'a': [1, 4, 7], 'b': [2, 5, 8], 'c': [3, 6, 9]}
or:
In [9]: dict(zip(keys, map(list, zip(*values))))
Out[9]: {'a': [1, 4, 7], 'b': [2, 5, 8], 'c': [3, 6, 9]}
Use:
{k: [d[i] for d in data] for i, k in enumerate(keys)}
Example:
>>> data=[[1422029700000, 230.84, 230.42, 230.31, 230.32, 378], [1422029800000, 231.84, 231.42, 231.31, 231.32, 379]]
>>> keys = ["a", "b", "c"]
>>> {k: [d[i] for d in data] for i, k in enumerate(keys)}
{'c': [230.42, 231.42], 'a': [1422029700000, 1422029800000], 'b': [230.84, 231.84]}
Your question has everything in a list so if you want a list of dicts:
l1= [[1422029700000, 230.84, 230.42, 230.31, 230.32, 378], [1422029800000, 231.84, 231.42, 231.31, 231.32, 379]]
l2 = ['a', 'b', 'c', 'd', 'e',"f"] # added f to match length of sublists
print([{a:list(b)} for a,b in zip(l2,zip(*l1))])
[{'a': [1422029700000, 1422029800000]}, {'b': [230.84, 231.84]}, {'c': [230.42, 231.42]}, {'d': [230.31, 231.31]}, {'e': [230.32, 231.32]}, {'f': [378, 379]}]
If you actually want a dict use a dict comprehension with zip:
print({a:list(b) for a,b in zip(l2,zip(*l1))})
{'f': [378, 379], 'e': [230.32, 231.32], 'a': [1422029700000, 1422029800000], 'b': [230.84, 231.84], 'c': [230.42, 231.42], 'd': [230.31, 231.31]}
You example also has a list of keys shorter than the length of your sublists so zipping will actually mean you lose values from your sublists so you may want to address that.
If you are using python2 you can use itertools.izip:
from itertools import izip
print({a:list(b) for a,b in izip(l2,zip(*l1))

python sorting dictionary by length of values

I have found many threads for sorting by values like here but it doesn't seem to be working for me...
I have a dictionary of lists that have tuples. Each list has a different amount of tuples. I want to sort the dictionary by how many tuples each list contain.
>>>to_format
>>>{"one":[(1,3),(1,4)],"two":[(1,2),(1,2),(1,3)],"three":[(1,1)]}
>>>for key in some_sort(to_format):
print key,
>>>two one three
Is this possible?
>>> d = {"one": [(1,3),(1,4)], "two": [(1,2),(1,2),(1,3)], "three": [(1,1)]}
>>> for k in sorted(d, key=lambda k: len(d[k]), reverse=True):
print k,
two one three
Here is a universal solution that works on Python 2 & Python 3:
>>> print(' '.join(sorted(d, key=lambda k: len(d[k]), reverse=True)))
two one three
dict= {'a': [9,2,3,4,5], 'b': [1,2,3,4, 5, 6], 'c': [], 'd': [1,2,3,4], 'e': [1,2]}
dict_temp = {'a': 'hello', 'b': 'bye', 'c': '', 'd': 'aa', 'e': 'zz'}
def sort_by_values_len(dict):
dict_len= {key: len(value) for key, value in dict.items()}
import operator
sorted_key_list = sorted(dict_len.items(), key=operator.itemgetter(1), reverse=True)
sorted_dict = [{item[0]: dict[item [0]]} for item in sorted_key_list]
return sorted_dict
print (sort_by_values_len(dict))
output:
[{'b': [1, 2, 3, 4, 5, 6]}, {'a': [9, 2, 3, 4, 5]}, {'d': [1, 2, 3, 4]}, {'e': [1, 2]}, {'c': []}]

Categories