I imported a .csv file using csv.DictReader
and converted the dictionaries into a list:
dataset = list(file.csv)
In this list of dictionaries I need to count the number of type 1 and type 2 actions (sum of them) for each year. I would like to avoid using repeat loops and just use reduce
and/or map
my_dict1 = {"Date": 2021-01-01, "Action1": 2, "Action2": 3}
my_dict1 = {"Date": 2021-02-01, "Action1": 3, "Action2": 3}
my_dict1 = {"Date": 2020-02-01, "Action1": 10, "Action2":9}
my_dict1 = {"Date": 2020-03-01, "Action1": 0, "Action2": 5}
I need the following output:
(2021, 11)
(2020, 24)
CodePudding user response:
As I understand from your question, you have a list of dicts, each of them composed in the following manner:
{"Date": "2021-01-01", "Action1": 2, "Action2": 3}
Date being a string and Action1 and Action2 being integers.
You need to get the sum of all actions for each separate year using only map and reduce and no loops (actually reduce and map implement loops in the background, but ok).
First thing to do is define a function to sum the actions in a dict and marks them with the correct year:
def sum_actions(dict_input: dict) -> dict:
date_of_actions = dict_input["Date"][0:4]
sum_of_actions = dict_input["Action1"] dict_input["Action2"]
return {"Date": date_of_actions, "Sum": sum_of_actions}
now you can just map this function to the list of dicts:
mapped_list = map(sum_actions, dataset)
From this you obtain a list of dicts (actually a map object that can be converted to a list) containing the year of entry and the sum of its actions:
[
{"Date" : "2021", "Sum": 12},
{"Date" : "2020", "Sum": 8},
...,
{"Date" : "2021", "Sum": 15},
]
Now you can store the sum of each year inside an object (I'll be using a dict).
You can just develop a function that will add the each entry to the sum inside a dict and pass it to reduce with an empty dict as initializer:
from functools import reduce
def sum_actions_in_year(value, element):
element_year = element["Date"]
element_sum = element["Sum"]
if value.get(element_year):
value[element_year] = value[element_year] element_sum
else:
value[element_year] = element_sum
return value
result = reduce(sum_actions_in_year, mapped_list, {})
This will return a dict with the following key-value pairs:
{YEAR: SUM_OF_YEAR,
YEAR: SUM_OF_YEAR}
If the answer needs to be in tupples you can just convert it:
list_of_tuples = list(result.items())
CodePudding user response:
(1) Create list llst
of year-action total pairs from the list of dictionaries,
(2) Using functools.reduce
, create a dictionary in which the key-value pairs denote year-actions pairs, by adding the second items of tuples in llst
if the first items match.
from functools import reduce
def add(d, x):
d[x[0]] = d.get(x[0], 0) x[1]
return d
llst = map(lambda x: (int(x['Date'].split('-')[0]), x.get('Action1', 0) x.get('Action2', 0)), lst)
out = list(reduce(add, llst, {}).items())
Output:
[(2021, 11), (2020, 24)]