Related
I have a list of dictionaries like this.
fruit = [{"apple": 10, "pear": 20, "banana": 30, "strawberry": 50},
{"apple": 12, "pear": 5, "banana": 20, "strawberry": 5},
{"apple": 15, "pear": 26, "banana": 32, "strawberry": 8}]
Can I write an reduce function in one line(with lambda argument) to get a new dictionary with the same keys. The value to each key of the new dictionary is the sum of all the values to the corresponding key. The expected output should be a dictionary as follows:
{'apple': 37.0, 'pear': 51.0, 'banana': 82.0, 'strawberry': 63.0}
Util-heavy approach:
from operator import add
from collections import Counter
from functools import reduce
reduce(add, map(Counter, fruit))
# Counter({'banana': 82, 'strawberry': 63, 'pear': 51, 'apple': 37})
Or maybe more instructive for the beginner, writing an add for two dicts:
def add(d1, d2):
return {k: d1.get(k, 0) + d2.get(k, 0) for k in d1.keys() | d2.keys()}
reduce(add, fruit)
A dict-comprehension can do the work of merging two dicts like this:
>>> from functools import reduce
>>> fruit = [{"apple": 10, "pear": 20, "banana": 30, "strawberry": 50},
... {"apple": 12, "pear": 5, "banana": 20, "strawberry": 5},
... {"apple": 15, "pear": 26, "banana": 32, "strawberry": 8}]
>>> reduce(lambda a, b: {k: a[k] + v for k, v in b.items()}, fruit)
{'apple': 37, 'pear': 51, 'banana': 82, 'strawberry': 63}
This does require that all dicts have the same keys, otherwise some will be dropped. The more complete version is this, which does get pretty unwieldy as a reduce-lambda though:
reduce(lambda a, b: {k: a.get(k, 0) + b.get(k, 0) for k in a.keys() | b.keys()}, fruit)
The following approach uses a dict comprehension and no imports. I don't recommend to use it however:
{k: sum(f.get(k,0) for f in fruit) for k in {k for f in fruit for k in f}}
# | |
# +-- set of all fruit keys --+
I have the following dictionary
d= {"Month":[1,2,3,4,5,6],"Rain":[30,40,50,20,30,70]}
I want to select certain Rain by ordered by Month, so I get
For example
new_d= {"Month":[2,4,6],"Rain":[40,20,70]}
I'm thinking along this side of a code, I'm still new to coding please help how can I do it without dictionary comprehensions?
for key in d:
if filter_string in key:
# do something
else:
# do nothing, continue
see below
d = {"Month": [1, 2, 3, 4, 5, 6], "Rain": [30, 40, 50, 20, 30, 70]}
interesting_month = [2, 4, 6]
d1 = {'Month': [m for m in interesting_month], 'Rain': [d["Rain"][d['Month'].index(m)] for m in interesting_month]}
print(d1)
output
{'Month': [2, 4, 6], 'Rain': [40, 20, 70]}
first with the for-loop, then as comprehension - as addition to the previous answer:
d = {"Month":[1,2,3,4,5,6],"Rain":[30,40,50,20,30,70]}
#new_d = {"Month":[2,4,6],"Rain":[40,20,70]}
mths_to_choose = [2,4,6]
for keyval in d.items():
new_d[keyval[0]] = []
for i in mths_to_choose: # if filter_string in key: # do something
new_d[keyval[0]].append(keyval[1][i-1])
# else# do nothing, continue
print(new_d)
new_d = {ditms[0]: [ditms[1][i-1] for i in mths_to_choose] for ditms in d.items()}
print(new_d)
output:
{'Month': [2, 4, 6], 'Rain': [40, 20, 70]}
{'Month': [2, 4, 6], 'Rain': [40, 20, 70]}
I hope this might be helpful
d = {"Month": [1, 2, 3, 4, 5, 6], "Rain": [30, 40, 50, 20, 30, 70]}
#Creating a new dictionary
new_d = {}
#First Loop: will get the keys from your original dictionary
for keys in d:
#new_d[keys] = [] - will create an array value for each key found
new_d[keys] = []
#Second Loop: will get the values from the array on each key
for values in d[keys]:
#If the position of "values" is odd then is inserted on new_d[keys] with the append() method
if d[keys].index(values) % 2 != 0:
new_d[keys].append(values)
#Print the outcome
print(new_d)
d = {"Month":[1,2,3,4,5,6], "Rain":[30,40,50,20,30,70]}
#Desired Output: {"Month":[2,4,6],"Rain":[40,20,70]}
selected_month = [2,4,6] #list of months
new_d = {} #create a new dictionary to store selected month and rain
for key in d.items():
new_d[key[0]] = []
for i in selected_month:
new_d[key[0]].append(key[1][i-1])
print(new_d)
for example I have a dictionary:
dictA={"nest1":{"01feb":[1,2,3,4,5],"02feb":[1,7,8,9,10]},
"nest2":{"01feb":[1,2,3,4,5],"02feb":[6,4,8,10,10]}}
the list inside has the same length. I need to merge nest1 and nest2 as one dictionary, and the result should be like this:
dictA={"nest":{"01feb":[2,4,6,8,10],"02feb":[7,11,16,19,20]}}
You can use a dict comprehension, map() and zip() like this example (works with Python 2 and Python 3).
dictA = {'nest1': {'01feb': [1, 2, 3, 4, 5], '02feb': [1, 7, 8, 9, 10]},
'nest2': {'01feb': [1, 2, 3, 4, 5], '02feb': [6, 4, 8, 10, 10]}}
a = (v.items() for _, v in map(list, dictA.items()))
# You can also use another map():
# final = {'nest': {k: list(map(sum, zip(v,j))) for (k, v), (_, j) in zip(*a)}}
final = {'nest': {k: [m+n for m, n in zip(v, j)] for (k, v), (_, j) in zip(*a)}}
print(final)
Output:
{'nest': {'02feb': [7, 11, 16, 19, 20], '01feb': [2, 4, 6, 8, 10]}}
Plese find the below code for your query.
dictA={"nest1":{"01feb":[1,2,3,4,5],"02feb":[1,7,8,9,10]},
"nest2":{"01feb":[1,2,3,4,5],"02feb":[6,4,8,10,10]}}
result ={}
final_op = {}
for k,v in dictA.iteritems():
for nk,nv in v.iteritems():
if result.has_key(nk):
i=0
while i < len(result[nk]):
result[nk][i] += nv[i]
i += 1
else:
result[nk] = nv
final_op['nest'] = result
print final_op
Output:
{'nest': {'02feb': [7, 11, 16, 19, 20], '01feb': [2, 4, 6, 8, 10]}}
You have to traverse the dict and update the value in the iteration.
dictA={"nest1":{"01feb":[1,2,3,4,5],"02feb":[1,7,8,9,10]},
"nest2":{"01feb":[1,2,3,4,5],"02feb":[6,4,8,10,10]}}
def merge(dictA):
merge_dict = {}
for key in dictA:
for sub_key in dictA[key]:
if sub_key in merge_dict:
# update the nested value
merge_dict[sub_key] = [sum(x) for x in zip(*[merge_dict[sub_key], dictA[key][sub_key]])]
else:
merge_dict[sub_key] = dictA[key][sub_key]
return merge_dict
merge_dict = merge(dictA)
dictA.clear()
dictA["nest"] = merge_dict
print(dictA)
Here is a function to do what you're asking for:
def merge_nested(dictionary):
result = dict()
for nested in dictionary.values():
for key in nested.keys():
if key in result:
# We've already found it, add our values to it's
for i in range(len(result[key])):
result[key][i] += nested[key][i]
else:
result[key] = nested[key]
return {"nest":result}
With this function you get the following output:
>>> print(merge_nested({"nest1":{"01feb":[1,2,3,4,5],"02feb":[1,7,8,9,10]},"nest2":{"01feb":[1,2,3,4,5],"02feb":[6,4,8,10,10]}}))
{'nest': {'01feb': [2, 4, 6, 8, 10], '02feb': [7, 11, 16, 19, 20]}}
This is a modified version of #Arockia's answer here
A solution with groupby of itertools:
from itertools import chain, groupby
import operator
dictA={"nest1":{"01feb":[1,2,3,4,5],"02feb":[1,7,8,9,10]},
"nest2":{"01feb":[1,2,3,4,5],"02feb":[6,4,8,10,10]}}
A = {
"nest": dict(
(key, list(map(operator.add, *(v for _, v in group))))
for key, group in groupby(
sorted(
chain(*(v.iteritems() for v in dictA.values())) # Python 2
# chain(*(v.items() for v in dictA.values())) # Python 3
),
lambda x: x[0],
)
)
}
print(A)
Result:
{'nest': {'02feb': [7, 11, 16, 19, 20], '01feb': [2, 4, 6, 8, 10]}}
I have a data structure. A list of 4 dictionaries each with 4 keys and 3 values in a list.
dict_list = [0] {key1: [1, 2, 3]
key2: [4, 5, 6]
key3: [7, 8, 9]
key4: [10, 11, 12]
[1] {key1: [13.......]
key2: [16... etc.
I want to sum each sub column [1, 4, 7, 10]....[2,5,8,11] etc. into the form
new_dict_list = [0] {new_key: [(1+4+7+10), (2,5,8,11), (3,6,9,12)]
[1] {new_key2: [(13+16....) etc.
So I'm basically cascading each column within each dictionary.
I have a VERY explicit and long way to do it so far (checking the math is correct), is there any way to use list comprehensions for something this long-winded or is it not worth the effort in the end?
Use zip to group [1, 4, 7, 10]....[2,5,8,11]:
>>> d = dict_list[0]
>>> zip(*d.values())
[(7, 4, 1, 10), (8, 5, 2, 11), (9, 6, 3, 12)]
Use map to generate the new list:
>>> map(sum, zip(*d.values()))
[22, 26, 30]
If you are using python3.x, you need list(map...) to get the list.
You can use zip and sum function :
dict_lis=[{next(d.iterkeys()):map(sum,zip(*d.values()))} for d in dict_lis]
dict.iterkeys() will returns an iterator of dictionary keys which you can get the first key using next function.but note that it wouldn't return the first key in the order that you have defined your dictionaries.since dictionary items are not ordered you can use collections.OrderedDict to get a ordered dictionary.
Note that you shouldn't have same key in your dictionaries!since you can not use same key in the last combined dictionary!
example :
dict_lis=[{'key1': [1, 2, 3],'key2': [4, 5, 6],'key3': [7, 8, 9],'key4': [10, 11, 12]},{'key5': [13,14,15],'key6': [16,17,18]}]
print [{next(d.iterkeys()):map(sum,zip(*d.values()))} for d in dict_lis]
[{'key3': [22, 26, 30]}, {'key6': [29, 31, 33]}]
Original version using list comprehensions:
# set up the initial data
dict_list = []
dict_list.append({'key1': range(1,4),
'key2': range(4,7),
'key3': range(7,10),
'key4': range(10,13)})
dict_list.append({'key1': range(13,16),
'key2': range(16,19),
'key3': range(19,22),
'key4': range(22,25)})
# generate the new list
new_dict_list = []
for d in dict_list:
new_dict_list.append({'new_key': [sum(v[0] for v in d.values()),
sum(v[1] for v in d.values()),
sum(v[2] for v in d.values())] })
print new_dict_list
The output looks like this:
[{'new_key': [22, 26, 30]}, {'new_key': [70, 74, 78]}]
I have a list of lists. If there are subslists that have the first three elements in common , merge them into one list and add all the fourth elements.
The problem is best explained in code and the required output.
a_list = [['apple', 50, 60, 7],
['orange', 70, 50, 8],
['apple', 50, 60, 12]]
# output:
# [['apple', 50, 60, 19], ['orange', 70, 50, 8]]
I already have code for a similar problem (given to me by another user in Stack Overflow some time ago), but i don't understand it completely so I'm unable to modify it accordingly. What this code does is it checks if the 0th and 2nd elements are the same, if they are, it merges the sublists, adding the 1st and 3th element:
import defaultdict
data = [['42x120x1800', 50, '50x90x800', 60],
['42x120x1800', 8, '50x90x800', 10],
['2x10x800', 5, '5x9x80', 6]]
d = defaultdict(lambda :[0, 0])
for sub_list in data:
key = (sub_list[0], sub_list[2])
d[key][0] += sub_list[1]
d[key][1] += sub_list[3]
new_data = [[key[0], val[0], key[1], val[1]] for key, val in d.iteritems()]
# [['2x10x800', 5, '5x9x80', 6], ['42x120x1800', 58, '50x90x800', 70]]
How should the code be modified to fit to my new problem? I'd really appreciate if you could also take the time and explain the code thoroughly, too.
You can use the same principle, by using the first three elements as a key, and using int as the default value factory for the defaultdict (so you get 0 as the initial value):
from collections import defaultdict
a_list = [['apple', 50, 60, 7],
['orange', 70, 50, 8],
['apple', 50, 60, 12]]
d = defaultdict(int)
for sub_list in a_list:
key = tuple(sub_list[:3])
d[key] += sub_list[-1]
new_data = [list(k) + [v] for k, v in d.iteritems()]
If you are using Python 3, you can simplify this to:
d = defaultdict(int)
for *key, v in a_list:
d[tuple(key)] += v
new_data = [list(k) + [v] for k, v in d.items()]
because you can use a starred target to take all 'remaining' values from a list, so each sublist is assigned mostly to key and the last value is assigned to v, making the loop just that little simpler (and there is no .iteritems() method on a dict in Python 3, because .items() is an iterator already).
So, we use a defaultdict that uses 0 as the default value, then for each key generated from the first 3 values (as a tuple so you can use it as a dictionary key) sum the last value.
So for the first item ['apple', 50, 60, 7] we create a key ('apple', 50, 60), look that up in d (where it doesn't exist, but defaultdict will then use int() to create a new value of 0), and add the 7 from that first item.
Do the same for the ('orange', 70, 50) key and value 8.
for the 3rd item we get the ('apple', 50, 60) key again and add 12 to the pre-existing 7 in d[('apple', 50, 60)]. for a total of 19.
Then we turn the (key, value) pairs back into lists and you are done. This results in:
>>> new_data
[['apple', 50, 60, 19], ['orange', 70, 50, 8]]
An alternative implementation that requires sorting the data uses itertools.groupby:
from itertools import groupby
from operator import itemgetter
a_list = [['apple', 50, 60, 7],
['orange', 70, 50, 8],
['apple', 50, 60, 12]]
newlist = [list(key) + [sum(i[-1] for i in sublists)]
for key, sublists in groupby(sorted(a_list), key=itemgetter(0, 1, 2))]
for the same output. This is going to be slower if your data isn't sorted, but it's good to know of different approaches.
I'd do something like this:
>>> a_list = [['apple', 50, 60, 7],
... ['orange', 70, 50, 8],
... ['apple', 50, 60, 12]]
>>>
>>> from collections import defaultdict
>>> d = defaultdict(list)
>>> from operator import itemgetter
>>> getter = itemgetter(0,1,2)
>>> for lst in a_list:
... d[getter(lst)].extend(lst[3:])
...
>>> d
defaultdict(<type 'list'>, {('apple', 50, 60): [7, 12], ('orange', 70, 50): [8]})
>>> print [list(k)+v for k,v in d.items()]
[['apple', 50, 60, 7, 12], ['orange', 70, 50, 8]]
This doesn't give the sum however. It could be easily be fixed by doing:
print [list(k)+[sum(v)] for k,v in d.items()]
There isn't much of a reason to prefer this over the slightly more elegant solution by Martijn, other than it will allow the user to have an input list with more than 4 items (with the latter elements being summed as expected). In other words, this would pass the list:
a_list = [['apple', 50, 60, 7, 12],
['orange', 70, 50, 8]]
as well.
Form the key from [:3] so that you get the first 3 elements.