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

Как использовать функциональное программирование для повторения и поиска максимального количества пяти последовательных номеров в списке?

Мне нужно использовать функциональное программирование для реализации следующей функции, которая принимает список чисел от 0 до 9. Цель состоит в том, чтобы найти пять последовательных элементов списка, которые имеют наибольший продукт. Функция должна возвращать кортеж индекса наибольшего продукта и значение наибольшего продукта без, используя максимальную функцию.

Я могу легко реализовать это без функционального программирования, но мне не удается реализовать его без каких-либо циклов. Это мой подход до сих пор, но часть, на которую я застрял, - это то, как прокручивать массив, чтобы найти эти последовательные пять чисел без циклов. Я пытаюсь использовать карту, чтобы сделать это, но я не думаю, что это правильно. Можно ли каким-либо образом включить перечисление? Любая помощь приветствуется.

def find_products(L):
    val = map(lambda a: reduce(lambda x,y: x*y, L),L)
    print (val)
4b9b3361

Ответ 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)