Подтвердить что ты не робот

Как работает функция сокращения?

Насколько я понимаю, функция уменьшения принимает список l и функцию f. Затем он вызывает функцию f для первых двух элементов списка, а затем повторно вызывает функцию f со следующим элементом списка и предыдущим результатом.

Итак, я определяю следующие функции:

Следующая функция вычисляет факториал.

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


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

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

Теперь, не должно ли это дать мне ((1! * 3!) * 1!) = 6? Но вместо этого он дает 720. Почему 720? Похоже, что факториал тоже 6. Но мне нужно понять, почему.

Может ли кто-нибудь объяснить, почему это происходит, и обход?

Я в основном хочу вычислить произведение факториалов всех записей в списке. План резервного копирования - запустить цикл и вычислить его. Но я бы предпочел использовать сокращение.

4b9b3361

Ответ 1

Хорошо, получилось:

Мне нужно сначала сопоставить числа с их факториалами, а затем вызвать сокращение с помощью оператора умножения.

Итак, это сработало бы:

lst_fact = map(fact, lst)
reduce(operator.mul, lst_fact)

Ответ 2

Другие ответы велики. Я просто добавлю иллюстрированный пример, который мне очень хорошо понимает reduce():

>>> reduce(lambda x,y: x+y, [47,11,42,13])
113

будет вычисляться следующим образом:

введите описание изображения здесь

(Источник) (mirror)

Ответ 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() целесообразно применять факториал к самому правому аргументу:

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)

С этой небольшой ревизией код производит 6, как вы ожидали: -)

Ответ 4

Ваша функция вызывает fact() для обоих аргументов. Вы вычисляете ((1! * 3!)! * 1!). Обходной путь состоит в том, чтобы вызвать его только по второму аргументу и передать reduce() начальное значение 1.

Ответ 5

Из документации Python reduce,

reduce (функция, последовательность) возвращает одно значение, построенное путем вызова (двоичной) функции по первым двум элементам последовательности, затем по результату и следующему элементу и т.д.

Итак, шаг за шагом. Он вычисляет reduce_func первых двух элементов, reduce_func(1, 3) = 1! * 3! = 6. Затем он вычисляет reduce_func результата и следующий элемент: reduce_func(6, 1) = 6! * 1! = 720.

Вы пропустили это, когда результат первого вызова reduce_func передается как вход ко второму, он факторизуется перед умножением.

Ответ 6

Ну, во-первых, ваш reduce_func не имеет структуры складки; это не соответствует вашему описанию складки (что правильно).

Структура складки: def foldl(func, start, iter): return func(start, foldl(func, next(iter), iter)

Теперь ваша функция fact не работает с двумя элементами - она ​​просто вычисляет факториал.

Итак, в общем, вы не используете сгиб, и с этим определением factorial вам не нужно.

Если вы хотите поиграть с факториалом, посмотрите y-combinator: http://mvanier.livejournal.com/2897.html

Если вы хотите узнать о сгибе, посмотрите на мой ответ на этот вопрос, который демонстрирует его использование для вычисления кумулятивных дробей: создание совокупного процента из словаря данных

Ответ 7

Вы также можете использовать факторное использование.

def factorial(n):
  return(reduce(lambda x,y:x*y,range(n+1)[1:]))

Ответ 8

Сокращает выполнение функции в параметре # 1 последовательно через значения, предоставленные итератором в параметре # 2

print '-------------- Example: Reduce(x + y) --------------'

def add(x,y): return x+y
x = 5
y = 10

import functools
tot = functools.reduce(add, range(5, 10))
print 'reduce('+str(x)+','+str(y)+')=' ,tot

def myreduce(a,b):
    tot = 0
    for i in range(a,b):
        tot = tot+i
        print i,tot
    print 'myreduce('+str(a)+','+str(b)+')=' ,tot

myreduce(x,y)

print '-------------- Example: Reduce(x * y) --------------'

def add(x,y): return x*y
x = 5
y = 10

import functools
tot = functools.reduce(add, range(5, 10))
print 'reduce('+str(x)+','+str(y)+')=' ,tot

def myreduce(a,b):
    tot = 1
    for i in range(a,b):
        tot = tot * i
        print i,tot
    print 'myreduce('+str(a)+','+str(b)+')=' ,tot

myreduce(x,y)