了解使用枚举减少列表列表
Understanding reduce with enumerate for a list of lists
我正在尝试将第一个列表的第一个数字 1 与第二个列表的第二个数字 5 相乘,依此类推以获得列表列表。例如,对于 [[1, 2, 3], [4, 5, 6], [7, 8, 9]],我想得到 1*5*9。
虽然有很多方法可以做到这一点,但我想知道 reduce 如何处理枚举:
def test(m):
return reduce(lambda a, b: a[1][a[0]]*b[1][b[0]], enumerate(m))
print test([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
我会认为开头的a
是(0,[1,2,3])所以a[1]是[1,2,3],a[0]是0,所以 a[1][a[0]] 是 1。
但是,我得到以下异常:
return reduce(lambda a, b: a[1][a[0]]*b[1][b[0]], enumerate(mat))
TypeError: 'int' object has no attribute '__getitem__'
为什么 a
是整数?
您的最终值和中间值是简单的整数。所以你应该从 1
开始,然后 lambda 将始终得到一个整数 a
,即到目前为止的乘积。而 b
将是下一个枚举项。所以这是如何做到的:
>>> reduce(lambda a, b: a * b[1][b[0]],
enumerate([[1, 2, 3], [4, 5, 6], [7,8,9]]), 1)
45
Python 2 仍然允许这样做,顺便说一句:
>>> reduce(lambda a, (i, b): a * b[i],
enumerate([[1, 2, 3], [4, 5, 6], [7,8,9]]), 1)
45
因此,由于您试图获得对角线数字相乘的最终值,这就是 O 的做法:
示例:
def idiagonal(xs_of_ys):
for i, x in enumerate(xs_of_ys):
for j, y in enumerate(x):
if i == j:
yield y
print reduce(lambda x, y: x * y, idiagonal(xs), 1) # prints 45
根据您在其中一条评论中的解释 - 您正在尝试乘以矩阵的对角线元素,现在我明白您为什么要 'enumerate' - 这确实是正确的,因为您想要得到那个指数。所以下面的代码会为你做到这一点。
首先 map 获取列表中的所有必需元素,然后 reduce 将它们乘以所需的值。注意:有几点需要注意,enumerate 会给你一个元组,所以你必须在 map lambda 中将它添加为 (x,y)。
a = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
reduce(lambda p,q: p*q, map(lambda (x,y): y[x], enumerate(a)), 1)
或
reduce(lambda p,q: p*q, [y[x] for (x,y) in enumerate(a)], 1)
编辑:添加了列表理解版本而不是 map-lambda。
请注意,列表理解版本与上述答案几乎一样快(只慢了大约 10%),为了可读性,我愿意换它。
尽管 Stefan 的回答在功能上是完美的,但我想指出...我们不是编译器,您知道。没有什么能阻止我们写一些更具可读性的东西,甚至可以在不解释任何事情的情况下说明你正在尝试做的事情:
from collections import namedtuple
Row = namedtuple('Row', ['num', 'columns'])
m = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
reduce(lambda result, row: result * row.columns[row.num],
(Row(*data) for data in enumerate(m)), 1)
查看 reduce 函数,现在我们知道您要在列号 = 行号的项目上累积。如果那不拼对角线,我不知道是什么:)
我正在尝试将第一个列表的第一个数字 1 与第二个列表的第二个数字 5 相乘,依此类推以获得列表列表。例如,对于 [[1, 2, 3], [4, 5, 6], [7, 8, 9]],我想得到 1*5*9。
虽然有很多方法可以做到这一点,但我想知道 reduce 如何处理枚举:
def test(m):
return reduce(lambda a, b: a[1][a[0]]*b[1][b[0]], enumerate(m))
print test([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
我会认为开头的a
是(0,[1,2,3])所以a[1]是[1,2,3],a[0]是0,所以 a[1][a[0]] 是 1。
但是,我得到以下异常:
return reduce(lambda a, b: a[1][a[0]]*b[1][b[0]], enumerate(mat))
TypeError: 'int' object has no attribute '__getitem__'
为什么 a
是整数?
您的最终值和中间值是简单的整数。所以你应该从 1
开始,然后 lambda 将始终得到一个整数 a
,即到目前为止的乘积。而 b
将是下一个枚举项。所以这是如何做到的:
>>> reduce(lambda a, b: a * b[1][b[0]],
enumerate([[1, 2, 3], [4, 5, 6], [7,8,9]]), 1)
45
Python 2 仍然允许这样做,顺便说一句:
>>> reduce(lambda a, (i, b): a * b[i],
enumerate([[1, 2, 3], [4, 5, 6], [7,8,9]]), 1)
45
因此,由于您试图获得对角线数字相乘的最终值,这就是 O 的做法:
示例:
def idiagonal(xs_of_ys):
for i, x in enumerate(xs_of_ys):
for j, y in enumerate(x):
if i == j:
yield y
print reduce(lambda x, y: x * y, idiagonal(xs), 1) # prints 45
根据您在其中一条评论中的解释 - 您正在尝试乘以矩阵的对角线元素,现在我明白您为什么要 'enumerate' - 这确实是正确的,因为您想要得到那个指数。所以下面的代码会为你做到这一点。
首先 map 获取列表中的所有必需元素,然后 reduce 将它们乘以所需的值。注意:有几点需要注意,enumerate 会给你一个元组,所以你必须在 map lambda 中将它添加为 (x,y)。
a = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
reduce(lambda p,q: p*q, map(lambda (x,y): y[x], enumerate(a)), 1)
或
reduce(lambda p,q: p*q, [y[x] for (x,y) in enumerate(a)], 1)
编辑:添加了列表理解版本而不是 map-lambda。
请注意,列表理解版本与上述答案几乎一样快(只慢了大约 10%),为了可读性,我愿意换它。
尽管 Stefan 的回答在功能上是完美的,但我想指出...我们不是编译器,您知道。没有什么能阻止我们写一些更具可读性的东西,甚至可以在不解释任何事情的情况下说明你正在尝试做的事情:
from collections import namedtuple
Row = namedtuple('Row', ['num', 'columns'])
m = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
reduce(lambda result, row: result * row.columns[row.num],
(Row(*data) for data in enumerate(m)), 1)
查看 reduce 函数,现在我们知道您要在列号 = 行号的项目上累积。如果那不拼对角线,我不知道是什么:)