【问题标题】:Understanding reduce with enumerate for a list of lists使用枚举了解 reduce 以获取列表列表
【发布时间】:2015-08-02 13:00:15
【问题描述】:

我正在尝试将第一个列表的第一个数字 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 是整数?

【问题讨论】:

  • 完全不确定你要做什么——枚举一个列表会给你索引和值(如果你想对索引做一些事情)。否则无需“枚举”。所以我想这有问题。因此,根据您的输入-绝对不清楚您要做什么。如果您想在列表中添加多个内容,请清楚您的输入和预期输出是什么。不幸的是,你的帖子混合了问题和实验——让人无法理解你想要做什么!

标签: python list reduce enumerate


【解决方案1】:

根据您在其中一个 cmets 中的解释-您正在尝试将矩阵的对角元素相乘,现在我明白您为什么要“枚举”-这确实是正确的,因为您想获得该索引。因此,以下代码将为您做到这一点。

首先 map 获取列表中所有需要的元素,然后 reduce 将它们乘以所需的值。注意:有几点需要注意, enumerate 会为您提供一个元组,因此您必须在地图 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 Pochman 的回答来计时这个答案。正如预期的那样,上面的答案比@Stefan Pochman 的答案慢了大约 50% - 这是直观的预期(在地图中建立列表),但并不慢 - 我认为。就我个人而言,我觉得这比x[1][x[0]] 更具可读性,但这只是个人喜好问题。
【解决方案2】:

您的最终值和中间值是简单的整数。所以你应该从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

【讨论】:

  • 我想做的(只是为了练习)更像是使用我在原始帖子中所说的列表列表的方阵对角元素的乘积。因此,对于特定情况,我所追求的是 1*5*9 。虽然有很多其他方法可以做到这一点(例如,使用 for 循环),但我选择使用 enumerate 来索引对角线元素,但还是坚持了我没想到的行为。具有 2 个元组的示例按我的预期工作:它产生 5 (=1*5),它应该是一个整数。
  • 啊该死,我误会了。检查我现在更新的答案的顶部。其余部分仍然有效,所以我暂时将其留在那里。
  • @JustDoIt 现在我实际上改变了整个事情:-)
  • 谢谢,您的评论“您的最终值和中间值是简单整数”绝对让我清醒。感谢您的帮助。
  • @JustDoIt 是的,a 是整数确实是您错过的唯一部分。你把所有更难的部分都做好了:-)
【解决方案3】:

尽管 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函数,现在我们知道您要在列号=行号的项目上进行累加。如果那不拼写对角线,我不知道是什么:)

【讨论】:

    【解决方案4】:

    因此,由于您试图达到对角线数字相乘的最终值,这就是 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
    

    【讨论】:

    • 这不是我想做的。我想为特定示例乘以 1*5*9,正如我在原始帖子中所说,我使用枚举来选择数字(第一个列表中的第一个数字,第二个列表中的第二个数字,依此类推.)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2022-11-23
    • 2011-03-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-06-02
    相关资源
    最近更新 更多