2017-11-18 307 views
13

我必須使用函數式編程來實現以下函數,其中包含從0到9的數字列表。目標是找到列表中具有最大產品的五個連續元素。該函數應該使用函數返回最大產品索引的元組和最大產品而不使用的值。如何使用函數式編程迭代並在列表中查找五個連續數字的最大乘積?

我可以很容易地實現這個沒有函數式編程,但我沒有任何循環實現它。 這是迄今爲止我的方法,但我堅持的部分是如何循環訪問數組以找到沒有循環的連續五個數字。我正在嘗試使用地圖來做到這一點,但我不認爲這是正確的。有沒有可能以任何方式包含枚舉?任何幫助表示讚賞。

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

'map'和'reduce'使用'loops'幕後,試圖避免'列表comprehensions'例如使用循環將要相當困難,並沒有真正的好處。 –

+4

如果您使用遞歸,您幾乎可以直接避免循環。 Haskell這樣做。但是,Haskell對此進行了優化,Python可能不會。所以你會很快進入最大遞歸深度。 - 無論如何,你在動作風格上做什麼動機? –

+10

函數式編程=/=避免循環。 – trincot

回答

7

這不會有任何顯式循環或致電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)是在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))) 
    ... 
+0

這看起來不錯,可能與OP期待的最接近。 –

+0

順便說一句,你可以使用'win = zip(*(l [i:]爲我在範圍(5)))'中獲得更一般的答案。 –

+2

@EricDuminil是的,但如果列表很大'itertools.islice'應該是首選 – vaultah

7
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功能,我們發現產品中的最大值。

+1

如果我錯了,請糾正我,但是我們不能在函數式編程中使用條件語句嗎?或者列表理解中的任何循環? – ce1

+5

@ comp.eng。函數式編程中的條件沒有任何問題。Haskell有,如果,守衛子句和模式匹配,所有形式的條件 - 沒有辦法停止無條件遞歸。 – Mephy

2

你可以做到以下幾點:

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

該算法可以進一步改進,以避免重新計算子產品,但使用「滾動產品」,即更新爲您從左至右減少,由元素除以被刪除,並乘以新添加的元素。

0

這裏是一個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)
0

想用最大一個襯層,沒有最大嘗試這種

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 
+0

max禁止:)。 –

+0

@ B.M。我更新了我的代碼,希望你喜歡它 –

0

該解決方案使用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) 
0

勢在必行範式往往是:

state = state0 
while condition: 
    # change state 

這是編程很多人的「自然」的方式,你知道如何這樣做。

functional paradigm禁止變量,這有一些優勢。它適用於通過參數(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]) 

無以外的功能已被定義。

您甚至可以定義沒有這樣做的函數,例如參見here,但可讀性受損甚至更多。

執行命令

In [1]: f([random.randint(0,9) for i in range (997)],0,0,0) 
Out[1]: (386, 59049)     

Python的限制通過遞歸深度設置爲2000這種方法,並從Python 3中,由模塊functools在隱藏的功能的工具。

0

使用recursion

首先,我們需要創建一個純Python的解決方案一recursivefunction找到的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在另一個recursivefunction解決你的問題:

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) 
+0

你請求了一些反饋。這段代碼看起來很合理。您最終會遇到Python中最大遞歸深度的問題。另外,在Python中調用函數的開銷不可忽略,因爲它們都是虛擬的。所以我會認爲使用'reduce'和'map'會更快,更容易閱讀。我仍然不明白OP的動機。 –

+0

@MartinUeding是的,我沒有考慮最大遞歸深度優點。我同意,OP要的是不實際的 –

相關問題