Как использовать функциональное программирование для повторения и поиска максимального количества пяти последовательных номеров в списке?
Мне нужно использовать функциональное программирование для реализации следующей функции, которая принимает список чисел от 0 до 9. Цель состоит в том, чтобы найти пять последовательных элементов списка, которые имеют наибольший продукт. Функция должна возвращать кортеж индекса наибольшего продукта и значение наибольшего продукта без, используя максимальную функцию.
Я могу легко реализовать это без функционального программирования, но мне не удается реализовать его без каких-либо циклов.
Это мой подход до сих пор, но часть, на которую я застрял, - это то, как прокручивать массив, чтобы найти эти последовательные пять чисел без циклов. Я пытаюсь использовать карту, чтобы сделать это, но я не думаю, что это правильно. Можно ли каким-либо образом включить перечисление? Любая помощь приветствуется.
def find_products(L):
val = map(lambda a: reduce(lambda x,y: x*y, L),L)
print (val)
Ответы
Ответ 1
Это не имеет явных циклов или вызывает функцию max
. Функция предполагает, что в списке входных данных имеется не менее пяти элементов и выводится кортеж (start_index, max_product)
.
from functools import reduce, partial
import operator
def f(l):
win = zip(l, l[1:], l[2:], l[3:], l[4:])
products = map(partial(reduce, operator.mul), win)
return reduce(lambda x, y: x if x[1] > y[1] else y, enumerate(products))
In [2]: f([1, 2, 3, 4, 7, 8, 9])
Out[2]: (2, 6048)
In [3]: f([2, 6, 7, 9, 1, 4, 3, 5, 6, 1, 2, 4])
Out[3]: (1, 1512)
win = zip(l, l[1:], l[2:], l[3:], l[4:])
создает скользящий оконный итератор размером 5 по списку ввода. products = map(partial(reduce, operator.mul), win)
- это итератор, вызывающий partial(reduce, operator.mul)
(переводит на reduce(operator.mul, ...)
) на каждый элемент из win
. reduce(lambda x, y: x if x[1] > y[1] else y, enumerate(products))
добавляет счетчик к products
и возвращает пара индексных значений с наивысшим значением.
Если вам нужна более общая версия и/или список ввода большой, вы должны использовать itertools.islice
:
from itertools import islice
def f(l, n=5):
win = zip(*(islice(l, i, None) for i in range(n)))
...
В приведенном выше коде технически используется выражение генератора, которое представляет собой цикл. Чистая функциональная версия, которая может выглядеть как
from itertools import islice
def f(l, n=5):
win = zip(*map(lambda i: islice(l, i, None), range(n)))
...
Ответ 2
from functools import reduce #only for python3, python2 doesn't need import
def find_products(L):
if len(L)==0:
return 0
if len(L) <= 5:
return reduce( lambda x,y:x*y, L)
pdts = ( reduce(lambda a,b:a*b,L[pos:pos+5]) for pos in range(len(L)-4)) # or pdts = map(lambda pos: reduce(lambda a,b:a*b,L[pos:pos+5],0),range(len(L)-4))
mx = reduce(lambda x,y: x if x>y else y, pdts)
return mx
pdts
содержит все возможные 5 кортежей, а затем используя reduce
, чтобы имитировать функцию max
, мы находим максимум среди продуктов.
Ответ 3
Вы можете сделать следующее:
- Для каждого индекса запуска в
range(0, len(L) - 5)
- Сопоставьте индекс с кортежем
start
и продуктом элементов L[start:start + 5]
- Сократите кортежи до наивысшего продукта
- Получить первое значение полученного кортежа = начальный индекс из 5 элементов, которые имеют наивысший продукт
- Вернуть срез
L[result:result + 5]
Этот алгоритм можно было бы дополнительно улучшить, чтобы избежать повторного вычисления подфайлов, но использовать "скользящий продукт", который обновляется по мере уменьшения слева направо, деления на элемент, который был отброшен, и умножения на новый элемент, который был добавлен.
Ответ 4
Вот решение Haskell, которое чисто функционально:
import Data.List
multiply :: [Int] -> Int
multiply = foldr (*) 1
consecutiveProducts :: [Int] -> [(Int,Int)]
consecutiveProducts xs =
[(i,multiply $ take 5 h) | (i,h) <- zipped, length h >= 5]
where
indices = reverse [0..(length xs)]
zipped = zip indices (tails xs)
myComp (i1,h1) (i2,h2) = compare h2 h1
main = print $ head $ sortBy myComp $ consecutiveProducts [4,5,3,1,5,3,2,3,5]
Вот что он делает:
- Начиная с последней строки, он вычисляет последовательные продукты из этого списка.
-
tails xs
дает все подмножества, начинающиеся с разных начальных значений:
> tails [4,5,3,1,5,3,2,3,5]
[[4,5,3,1,5,3,2,3,5],[5,3,1,5,3,2,3,5],[3,1,5,3,2,3,5],[1,5,3,2,3,5],[5,3,2,3,5],[3,2,3,5],[2,3,5],[3,5],[5],[]]
- Из этих хвостов мы берем только те, которые длиной не менее 5 элементов.
- Тогда мы
zip
их с натуральными числами, так что мы имеем начальный индекс, связанный с ним.
- Из каждого подмножества берутся первые пять элементов.
- Эти пять элементов передаются функции
multiply
. Там они сводятся к одному номеру продукта.
- После этого мы возвращаемся к последней строке, сортируем список по наименьшему значению продукта.
- Из полученного списка мы берем только первый элемент.
- И затем мы печатаем результат, который
(5,450)
для моих входных данных.
Ответ 5
хотите, чтобы один лайнер, используя max и без макс, попробуйте это
from numpy import prod
l=[2,6,7,9,1,4,3]
max([prod(l[i:i+5]) for i in range(len(l))])
sorted([prod(l[i:i+5]) for i in range(len(l))])[-1] // without max
Ответ 6
Это решение использует reduce
для расчета продукта на 5-значение, список понимание для создания всех этих продуктов, создание кортежа за то, что индекс идти с каждым, reduce
еще раз, чтобы получить лучший кортеж.Р >
Оператор if else
используется для обнаружения случая, когда на входе нет 5 значений.
from functools import reduce
def find_products(values):
return None if len(values) < 5 else reduce(
lambda best, this: this if this[1] > best[1] else best,
[(i, reduce(lambda a,b: a*b, values[i:i+5], 1)) for i in range(0, len(values)-4)]
)
result = find_products([1, 0, 8, 3, 5, 1, 0, 2, 2, 3, 2, 2, 1])
print (result)
Вывод для вызова примера:
(7, 48)
Ответ 7
Императивная парадигма часто:
state = state0
while condition:
# change state
Это "естественный" способ программирования для многих людей, и вы знаете, как это сделать.
Чистый функциональная парадигма запрещают переменные, которые имеют некоторые преимущества. Он работает с функциями, которые передаются через параметры (IN) и возвращаемые значения (OUT). Он часто использует рекурсивные функции.
Общая функциональная рекурсивная схема:
f = lambda *args : result(*args) if condition(*args) else f(*newparams(*args))
Здесь мы можем найти решение с (l,i,imax,prodmax)
в качестве параметров и:
condition = lambda l,i,_,__ : i>=len(l)-5
result = lambda _,__,*args : args
newparams = lambda l,i,imax,prodmax: (l, i+1, imax, prodmax) \
if l[i]*l[i+1]*l[i+2]*l[i+3]*l[i+4] <= prodmax \
else (l, i+1, i, l[i]*l[i+1]*l[i+2]*l[i+3]*l[i+4])
Определены функции, отличные от функций.
Вы даже не можете определить никаких функций для этого, например, здесь, но читаемость страдает еще больше.
Запуск:
In [1]: f([random.randint(0,9) for i in range (997)],0,0,0)
Out[1]: (386, 59049)
Python ограничивает этот подход, устанавливая рекурсивную глубину до 2000 и из Python 3, скрывая функциональные инструменты в модуле functools
.
Ответ 8
Решение Pure Python с использованием recursion
Сначала нам нужно создать recursive
function
, чтобы найти product
для list
:
def product(l, i=0, s=1):
s *= l[i]
if i+1 < len(l):
return product(l, i+1, s)
return s
который мы можем выполнить для:
>>> product([1, 2, 3])
6
>>> product([1, 1, 1])
3
>>> product([2, 2, 2])
8
Затем мы можем использовать этот function
в другом recursive
function
для решения вашей проблемы:
def find_products(l, i=0, t=(0, -1)):
p = product(l[i:i+5])
if p > t[1]:
t = (i, p)
if i+5 < len(l):
return find_products(l, i+1, t)
return t
который работает!
Вот несколько тестов, показывающих, что они работают:
>>> find_products([1, 1, 5, 5, 5, 5, 5, 1, 1])
(2, 3125)
>>> find_products([1, 1, 1, 1, 1, 0, 0, 0, 0])
(0, 1)
>>> find_products([1, 4, 5, 2, 7, 9, 3, 1, 1])
(1, 2520)