Python 中的 functools.reduce 未按预期工作
我想使用 functools.reduce 函数对列表中嵌套的字典键进行求和,
我可以使用以下简单程序在不使用 functools.reduce 函数的情况下完成此操作
dict1 = {'a': '1', 'b': '2'}
dict2 = {'a': '5', 'b': '0'}
dict3 = {'a': '7', 'b': '3'}
data_list = [dict1, dict2, dict3]
total_a = 0
total_b = 0
for record in data_list:
total_a += eval(record['a'])
total_b += eval(record['b'])
print(total_a)
print(total_b)
:不过,我说过,我想使用 functools.reduce 方法来产生相同的结果。
这是我尝试将 functools.reduce 与 lambda 表达式一起使用:
from functools import reduce
dict1 = {'a': '1', 'b': '2'}
dict2 = {'a': '5', 'b': '0'}
dict3 = {'a': '7', 'b': '3'}
data_list = [dict1, dict2, dict3]
total_a = reduce(lambda x, y: int(x['a']) + int(y['a']),data_list)
total_b = reduce(lambda x, y: int(x['b']) + int(y['b']),data_list )
print(total_a)
print(total_b)
不幸的是,我收到以下错误,但不知道原因:
TypeError: 'int' object is not subscriptable
有人知道我为什么收到此错误吗?
I would like to sum across keys of dictionaries nested within a list using the functools.reduce
function
I can accomplish this WITHOUT the functools.reduce
function with the following simple program:
dict1 = {'a': '1', 'b': '2'}
dict2 = {'a': '5', 'b': '0'}
dict3 = {'a': '7', 'b': '3'}
data_list = [dict1, dict2, dict3]
total_a = 0
total_b = 0
for record in data_list:
total_a += eval(record['a'])
total_b += eval(record['b'])
print(total_a)
print(total_b)
As I said however, I would like to produce the same results using the functools.reduce
method instead.
Here is my attempt at using functools.reduce
with a lambda expression:
from functools import reduce
dict1 = {'a': '1', 'b': '2'}
dict2 = {'a': '5', 'b': '0'}
dict3 = {'a': '7', 'b': '3'}
data_list = [dict1, dict2, dict3]
total_a = reduce(lambda x, y: int(x['a']) + int(y['a']),data_list)
total_b = reduce(lambda x, y: int(x['b']) + int(y['b']),data_list )
print(total_a)
print(total_b)
Unfortunately, I get the following error and do not know why:
TypeError: 'int' object is not subscriptable
Does someone know why I am getting this error?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
首先,让我们将样本减少到最小(双关语):
同样的错误。但请注意这一点:
这很有效。那么到底是怎么回事呢?为了简化起见,让我们将 lambda 表达式分配给一个变量:
Reduce 会像这样组合输入:
但是减少完整列表时会发生什么?其计算
结果为 因此会出错,因为它尝试从整数 3 访问项目
"a"
。基本上:传递给 reduce 的函数的输出必须可以作为其第一个参数。在您的示例中,lambda 期望字典作为其第一个参数并返回一个整数。
First, let's reduce (pun intended) the sample to a minimum:
Same error. But observe this:
That's working. So what's going on? For simplification, let's assign the lambda expression to a variable:
Reduce combines the input like this:
But what's happening when reducing the full list? This evaluates to
So this errors out because it tries to access item
"a"
from the integer 3.Basically: The output of the function passed to reduce must be acceptable as its first parameter. In your example, the lambda expects a dictionary as its first parameter and returns an integer.
您误解了
reduce()
的工作原理。在传递给它的函数中,它的第一个参数到目前为止是部分结果,与传递给reduce() 的可迭代对象没有直接关系。可迭代对象一次将一个元素传递给函数的第二个参数。由于您想要求和,因此“部分结果”的初始值需要为 0,并且还需要将其传递给reduce()
。因此,总而言之,这些行将打印您想要的内容:
编辑:用上面的
int()
替换eval()
,因此它与编辑的问题匹配。不过,这与答案无关。编辑2:你不断改变问题,但我不会不断改变答案来匹配;-)上面的代码完全回答了问题的早期版本,并且没有任何材料改变。完全相同的事情仍在发挥作用,并且需要完全相同的方法。
类型注释
虽然 Python 不需要显式类型声明,但有时它们会很有帮助。
如果您有一个
A
类型的可迭代传递对象,并且reduce()
的结果是B
类型,那么该对象的签名传递给reduce()
的第一个参数必须是在示例中,
A
是dict
,B
是int
。为两者传递一个指令是不可能的。这就是为什么我们需要在本例中指定B
(int
) 类型的初始值。在文档示例中,
A
和B
通常都是int
或float
。那么对于reduce()
的第一个参数来说,一个简单的 + 或 * 就已经是类型正确的了。You misunderstand how
reduce()
works. In the function passed to it, its first argument is a partial result so far, and has nothing directly to do with the iterable passed toreduce()
. The iterable is passed one element at a time, to the function's second argument. Since you want a sum, the initial value of the "partial result" needs to be 0, which also needs to be passed toreduce()
.So, in all, these lines will print what you want:
EDIT: replaced
eval()
withint()
above, so it matches the edited question. It's irrelevant to the answer, though.EDIT 2: you keep changing the question, but I'm not going to keep changing the answer to match ;-) The code just above fully answers an earlier version of the question, and nothing material has changed. Exactly the same things are still at work, and exactly the same kind of approach is needed.
Gloss on types
While Python doesn't require explicit type declarations, sometimes they can be helpful.
If you have an iterable delivering objects of type
A
, and the result ofreduce()
is of typeB
, then the signature of the the first argument passed toreduce()
must beIn the example,
A
isdict
andB
isint
. Passing a dict for both can't possibly work. That's essentially why we need to specifiy an initial value of typeB
(int
) in this case.In doc examples,
A
andB
are typically bothint
orfloat
. Then a simple + or * is already type-correct forreduce()
's first argument.缩减函数接收当前缩减值加上要缩减的下一个迭代项。诀窍在于选择减少值的样子。在您的情况下,如果您选择包含“a”和“b”的减少值的 2 项列表,则减少函数只会将下一个“a”和“b”添加到这些值中。减少最容易写成几个语句,因此应该从匿名 lambda 转移到常规函数。从
[0, 0]
的初始值设定项开始来保存简化的“a”和“b”,您将得到:The reduction function receives the current reduced value plus the next iterated item to be reduced. The trick is in choosing what that reduction value looks like. In your case, if you choose a 2 item list holding the reduced values of 'a' and 'b', then the reduction function just adds the next 'a' and 'b' to those values. The reduction is most easily written as a couple of statements so should be moved from an anonymous lambda to a regular function. Start with an initializer of
[0, 0]
to hold the reduced 'a' and 'b', and you get:由于我们要添加整数,因此
reduce
的替代方法是sum
:Since we're adding integers, an alternative to
reduce
issum
: