如何仅用 reduce 和 map 每年总结一本字典?

Posted

技术标签:

【中文标题】如何仅用 reduce 和 map 每年总结一本字典?【英文标题】:How to summarize a dictionary per year with only reduce and map? 【发布时间】:2022-01-18 21:29:26 【问题描述】:

我使用csv.DictReader 导入了一个 .csv 文件并将字典转换为一个列表:

dataset = list(file.csv)

在这个字典列表中,我需要计算每年类型 1 和类型 2 操作的数量(它们的总和)。我想避免使用重复循环,只使用reduce 和/或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

我需要以下输出:

(2021, 11)
(2020, 24)

【问题讨论】:

这是一个挑战,并且已经施加了这个限制。 我可以想象的是根据年份分离数据(使用条件或过滤器),然后添加每年的操作数,但这似乎不是最佳选择。我目前正在从 R 迁移到 Python,但仍然遇到一些困难。 挑战是使用纯语言和 Pandas 来完成这项任务。有了 Pandas,一切都变得更容易了,我设法做到了。但我在其他部分遇到了困难。 为什么它不是最佳选择?这里到底有什么问题?你实际上可以用一个 reduce 来做到这一点,尽管它会很丑陋且不符合 Python 标准 不,reduce 不像 R 中的 apply。Apply 像 map 【参考方案1】:

(1) 从字典列表中创建列表 llst 的年份-动作总对,

(2) 使用functools.reduce,创建一个字典,其中键值对表示年份-动作对,如果第一项匹配,则在llst 中添加元组的第二项。

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())

输出:

[(2021, 11), (2020, 24)]

【讨论】:

【参考方案2】:

据我了解,您有一个 dicts 列表,每个 dicts 都按以下方式组成:

"Date": "2021-01-01", "Action1": 2, "Action2": 3

日期是字符串,Action1 和 Action2 是整数。

您需要仅使用 map 和 reduce 而没有循环(实际上是在后台执行 reduce 和 map 循环,但是没问题)来获取每个单独年份的所有操作的总和。

首先要做的是定义一个函数来总结字典中的动作并用正确的年份标记它们:

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

现在您可以将此函数映射到字典列表:

mapped_list = map(sum_actions, dataset)

从中您可以得到一个字典列表(实际上是一个可以转换为列表的地图对象),其中包含进入的年份及其操作的总和:

[
"Date" : "2021", "Sum": 12,
"Date" : "2020", "Sum": 8,
...,
"Date" : "2021", "Sum": 15,
]

现在您可以将每年的总和存储在一个对象中(我将使用字典)。

您可以开发一个函数,将每个条目添加到字典内的总和中,并将其传递给以空字典作为初始化器的 reduce:

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, )

这将返回一个包含以下键值对的字典:

YEAR: SUM_OF_YEAR,
YEAR: SUM_OF_YEAR

如果答案需要在元组中,您可以将其转换:

list_of_tuples = list(result.items())

【讨论】:

以上是关于如何仅用 reduce 和 map 每年总结一本字典?的主要内容,如果未能解决你的问题,请参考以下文章

map()reduce()filter()总结

map,reduce,filter的总结(reduce还有点不懂,一会自己再看看)

hive如何调整map数和reduce数

map()reduce()filter()总结

如何确定 Hadoop map和reduce的个数

hadoop如何分配job来map和reduce