Ответ 1
Хорошо, получилось:
Мне нужно сначала сопоставить числа с их факториалами, а затем вызвать сокращение с помощью оператора умножения.
Итак, это сработало бы:
lst_fact = map(fact, lst)
reduce(operator.mul, lst_fact)
Насколько я понимаю, функция уменьшения принимает список 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
. Но мне нужно понять, почему.
Может ли кто-нибудь объяснить, почему это происходит, и обход?
Я в основном хочу вычислить произведение факториалов всех записей в списке. План резервного копирования - запустить цикл и вычислить его. Но я бы предпочел использовать сокращение.
Хорошо, получилось:
Мне нужно сначала сопоставить числа с их факториалами, а затем вызвать сокращение с помощью оператора умножения.
Итак, это сработало бы:
lst_fact = map(fact, lst)
reduce(operator.mul, lst_fact)
Другие ответы велики. Я просто добавлю иллюстрированный пример, который мне очень хорошо понимает reduce()
:
>>> reduce(lambda x,y: x+y, [47,11,42,13])
113
будет вычисляться следующим образом:
Самый простой способ понять 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, как вы ожидали: -)
Ваша функция вызывает fact()
для обоих аргументов. Вы вычисляете ((1! * 3!)! * 1!)
. Обходной путь состоит в том, чтобы вызвать его только по второму аргументу и передать reduce()
начальное значение 1.
Из документации Python reduce
,
reduce (функция, последовательность) возвращает одно значение, построенное путем вызова (двоичной) функции по первым двум элементам последовательности, затем по результату и следующему элементу и т.д.
Итак, шаг за шагом. Он вычисляет reduce_func
первых двух элементов, reduce_func(1, 3) = 1! * 3! = 6
. Затем он вычисляет reduce_func
результата и следующий элемент: reduce_func(6, 1) = 6! * 1! = 720
.
Вы пропустили это, когда результат первого вызова reduce_func
передается как вход ко второму, он факторизуется перед умножением.
Ну, во-первых, ваш 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
Если вы хотите узнать о сгибе, посмотрите на мой ответ на этот вопрос, который демонстрирует его использование для вычисления кумулятивных дробей: создание совокупного процента из словаря данных
Вы также можете использовать факторное использование.
def factorial(n):
return(reduce(lambda x,y:x*y,range(n+1)[1:]))
Сокращает выполнение функции в параметре # 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)