设v是数字列表
v = [3,5,2,4,8,6,1]
为什么以下代码找到max元素及其索引会出错? ('int'对象不可订阅)
reduce(lambda x,y: max(x[1],y[1]), enumerate(v))
P.S。我知道还有其他方法可以做到,比如下面的那个,但我想理解为什么前一个不起作用。
max(enumerate(v), key= lambda x: x[1])
后记
Simeon指出我的代码确实是错误的,因为lambda应该返回一个元组,而不是一个数字。理解这一点,我的代码可以通过以下方式轻松修复:
reduce(lambda x,y: x[1]<y[1] and y or x, enumerate(v))
顺便说一句,这比慢约30%
max(enumerate(v), key= lambda x: x[1])
答案 0 :(得分:6)
你问为什么以下不起作用:
reduce(lambda x,y: max(x[1],y[1]), enumerate(v))
让我们看看:您的输入是enumerate(v)
,它会迭代以下元素:
[(0, 3), (1, 5), (2, 2), (3, 4), (4, 8), (5, 6), (6, 1)]
您打算使用函数lambda x,y: max(x[1],y[1])
减少这些元素。根据{{3}},reduce将函数作为应用于iterable的两个元素的输入。这意味着它减少了两个元素并返回一个值,这是下一次reduce调用的参数之一。
这意味着x
和y
是元组。为了使上述工作,lambda函数的返回值需要再次成为元组,因为它在下一次缩减时再次使用。但是你返回一个整数,max
的结果。这就是您收到错误的原因:“'int'对象不可订阅”,因为x[1]
在x
为整数时不起作用。
答案 1 :(得分:2)
如何减少工作:
# type annotations:
# reduce(lambda X,X:X, [X,X..]) -> X
# SAME <-- result
# ↗ ↖
# SAME SAME]
# ↗ ↖
# SAME SAME,
# ↗ ↖
# [SAME, SAME,
>>> reduce(lambda a,b:[a,b], [1,2,3,4])
[[[1, 2], 3], 4]
这是使用种子(a.k.a. fold-left)减少的方式:
# type annotations:
# reduce(lambda REDU,ELEM:REDU, [ELEM,ELEM..], seed=REDU) -> REDU
# REDU <-- result
# ↗ ↖
# REDU ELEM]
# ↗ ↖
# REDU ELEM,
# ↗ ↖
# REDU ELEM,
# ↗ ↖
# REDU [ELEM,
>>> reduce(lambda a,b:[a,b], [1,2,3,4], 'seed')
[[[['seed', 1], 2], 3], 4]
你想:
maxValue,maxIndex = reduce(
lambda p1,p2: max(p1,p2),
((x,i) for i,x in enumerate(yourList))
)
关于reduce
的重要注意事项是类型。
*当您使用带有种子值的reduce(...)(在其他语言中称为fold
)时,返回类型将是种子的类型。
*正常使用reduce
时,它会忽略种子元素。如果列表中的所有元素都是相同类型(例如,您可以reduce(operator.mul, [1,2,3])
或reduce(operator.add, [1,2,3])
就好了,这很有用,因为减少的输出类型(int)与未减少的输入类型相同(两个整体))。但是返回类型将与列表元素的类型相同。
如果您的元素属于不同类型,则需要在fold
- 模式中使用reduce(...)(即使用带有右侧语义的种子)。 (另一种方法是特殊情况下你的lambda(非常难看)。)
更明确地说,您的预期返回类型是元组(最大元素及其索引,或相反)。但是,缩减函数的类型为tuple,tuple -> int
。这不起作用,因为它违反了减少功能需求的合同。