如何使用函数式编程迭代并找到列表中五个连续数字的最大乘积?

时间:2017-11-18 13:19:17

标签: python list lambda functional-programming

我必须使用函数式编程来实现以下函数,其中包含0到9之间的数字列表。目标是找到列表中具有最大乘积的五个连续元素。该函数应使用 max 函数返回最大产品索引的元组和最大产品的值

我可以在没有函数式编程的情况下轻松实现它,但是在没有任何循环的情况下实现它很困难。 到目前为止,这是我的方法,但我坚持的部分是如何遍历数组以找到没有循环的连续五个数字。我正在尝试使用map来做到这一点,但我不认为这是正确的。是否有可能以任何方式合并枚举?任何帮助表示赞赏。

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

8 个答案:

答案 0 :(得分: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 :(得分: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)是一个迭代器,在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 :(得分:2)

您可以执行以下操作:

  • 对于range(0, len(L) - 5)
  • 中的每个起始索引
  • 将索引映射到start的元组和项L[start:start + 5]的产品
  • 将元组减少到具有最高产品的元组
  • 获取结果元组的第一个值=具有最高乘积的5个元素的起始索引
  • 返回切片L[result:result + 5]

这个算法可以进一步改进,以避免重新计算子产品,但使用&#34;滚动产品&#34;,当你从左到右减少时,更新,除以被删除的元素,并乘以添加的新元素。

答案 3 :(得分: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)

答案 4 :(得分:0)

想要使用max而不使用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

答案 5 :(得分:0)

此解决方案使用reduce计算5值产品,列表理解以生成所有这些产品,使用索引创建元组创建,再次reduce以获得最佳元组

当输入中没有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)

答案 6 :(得分: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来限制此方法,并通过隐藏模块functools中的功能工具从Python 3中设置。

答案 7 :(得分:0)

使用recursion

的纯Python解决方案

首先,我们需要创建一个recursive function来查找product的{​​{1}}:

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