reduce方法的不同行为

时间:2015-06-29 17:36:28

标签: python lambda

我有一个数字列表。我想计算列表的某个子集的按位and。我使用了reduce方法。我认为这两种方法应该产生相同的结果。

table = [5, 10, 2, 6, 7, 18, 19, 1, 4, 9, 17, 8, 16, 0, 15, 11, 12, 13, 3, 14]
l = [0,1,2,3]
print reduce (lambda x,y:table[x]&table[y] , l ) 
print reduce (lambda x,y:x&y , [ table[x] for x in l ] )

但经过大量调试后我发现他们没有。我不明白背后的原因。

2 个答案:

答案 0 :(得分:3)

你误解了reduce()的作用。它使用前一次调用的结果调用lambda ,并从列表中调用下一个值。如果没有先前的值,则使用列表的第一个元素。

因此,x每次都会成为以前的结果,除了第一次。 将从列表推导中变为table[x],在不使用列表推导时也不会是列表中的值。

对于您的第一次reduce()电话,会发生这种情况:

  • x设置为0y设置为1。计算table[0] & table[1],结果为5 & 10,结果为0

  • x因此设置为0(之前的结果),y设置为l中的下一个值,因此2。计算table[0] & table[2]5 & 2,结果再次为0

  • x因此设置为0(之前的结果),y设置为l中的下一个值,因此3table[0] & table[3]计算得出5 & 6,结果现在为4

您的第二次reduce()来电直接来自table,因此您现在使用[5, 10, 2, 6]作为输入,在缩小时不再咨询table

  • x设为5y设为105 & 10 0

  • x因此设置为0(之前的结果),y设置为列表中的下一个值,因此2。计算0 & 2,结果再次为0

  • x因此设置为0(之前的结果),y设置为列表中的下一个值,因此6。计算0 & 6,结果再次为0

不同之处在于你误解了选择的table[x]值。

由于reduce()每次都会将调用应用于上一个结果,因此您应该将其视为一组链式调用。您的第一个reduce()可以写到:

table[table[table[0] & table[1]] & table[2]] & table[3]

,而您的第二个reduce()有效地计算:

((table[0] & table[1]) & table[2]) & table[3]

答案 1 :(得分:3)

理解reduce()的最简单方法是查看其纯Python等效代码:

def myreduce(func, iterable, start=None):
    it = iter(iterable)
    if start is None:
        try:
            start = next(it)
        except StopIteration:
            raise TypeError('reduce() of empty sequence with no initial value')
    accum_value = start
    for x in iterable:
        accum_value = func(accum_value, x)
    return accum_value

你可以看到,只有你的reduce_func()才能将factorial应用到最右边的参数:

def fact(n):
    if n == 0 or n == 1:
        return 1
    return fact(n-1) * n

def reduce_func(x,y):
    return x * fact(y)

lst = [1, 3, 1]
print reduce(reduce_func, lst)