簡體   English   中英

如何使用函數式編程來迭代和查找列表中五個連續數字的最大乘積?

[英]How to use functional programming to iterate and find maximum product of five consecutive numbers in a list?

我必須使用函數式編程來實現以下函數,該函數采用從0到9的數字列表。目標是找到列表中具有最大乘積的五個連續元素。 該函數應返回最大乘積的索引元組和最大乘積的值, 而不使用max函數。

我可以輕松地實現此功能而無需進行功能編程,但是我很難在沒有任何循環的情況下實現它。 到目前為止,這是我的方法,但是我堅持的部分是如何遍歷數組以查找連續的五個數字而沒有循環。 我正在嘗試使用地圖來做到這一點,但我認為這是不正確的。 是否可以通過任何方式合並枚舉? 任何幫助表示贊賞。

def find_products(L):
    val = map(lambda a: reduce(lambda x,y: x*y, L),L)
    print (val)
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函數,我們在乘積中找到最大值。

這沒有任何顯式循環或調用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)是一個迭代器reduce(operator.mul, ...)win每個元素上調用partial(reduce, operator.mul) (轉換為reduce(operator.mul, ...) )。 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)))
    ...

您可以執行以下操作:

  • 對於range(0, len(L) - 5)每個起始索引
  • 將索引映射到start的元組和項L[start:start + 5]的乘積
  • 將元組減少到產量最高的元組
  • 獲取結果元組的第一個值=乘積最高的5個元素的起始索引
  • 返回切片L[result:result + 5]

可以進一步改進該算法以避免重新計算子產品,而是使用“滾動產品”,該產品會隨着您從左到右的減少,除以被刪除的元素並乘以新的元素而進行更新。添加。

這是純粹功能的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)

想要一個使用最大和沒有最大的班輪試試這個

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

該解決方案使用reduce來計算5值乘積,生成所有這些乘積的列表理解,使索引與之對應的元組創建,再reduce以得到最佳元組。

if else輸入中沒有5個值,則使用if else運算符捕獲情況。

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)

命令式范例通常是:

 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模塊中來限制這種方法。

使用recursion純Python解決方案

首先,我們需要創建一個recursive function來查找listproduct

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)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM