web-dev-qa-db-fra.com

Comment utiliser la programmation fonctionnelle pour itérer et trouver le produit maximal de cinq nombres consécutifs dans une liste?

Je dois utiliser la programmation fonctionnelle pour implémenter la fonction suivante prend une liste de nombres allant de 0 à 9. Le but est de trouver les cinq éléments consécutifs de la liste qui ont le plus grand produit. La fonction doit renvoyer Tuple de l'index du plus grand produit et de la valeur du plus grand produit sans à l'aide de la fonction max .

Je peux facilement l'implémenter sans programmation fonctionnelle, mais j'ai du mal à l'implémenter sans boucles. C’est mon approche jusqu’à présent, mais la partie sur laquelle je suis coincé est la façon de parcourir le tableau pour trouver ces cinq nombres consécutifs sans boucles. J'essaie d'utiliser map pour faire cela, mais je ne pense pas que ce soit correct. Est-il possible d'incorporer énumérer de quelque manière que ce soit? Toute aide est appréciée.

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

Cela n'a pas de boucles explicites ou appelle la fonction max. La fonction suppose qu'il y a au moins cinq éléments dans la liste d'entrée et génère un Tuple (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:]) crée un itérateur de fenêtre coulissante de taille 5 sur la liste de saisie. products = map(partial(reduce, operator.mul), win) est un itérateur appelant partial(reduce, operator.mul) (traduit par reduce(operator.mul, ...)) sur chaque élément de win. reduce(lambda x, y: x if x[1] > y[1] else y, enumerate(products)) ajoute un compteur à products et renvoie la paire index-valeur avec la valeur la plus élevée.

Si vous avez besoin d'une version plus générale et/ou que la liste de saisie est volumineuse, utilisez itertools.islice:

from itertools import islice

def f(l, n=5):
    win = Zip(*(islice(l, i, None) for i in range(n)))
    ...

Le code ci-dessus utilise une expression génératrice qui est techniquement une boucle. Une version fonctionnelle pure de cela pourrait ressembler

from itertools import islice

def f(l, n=5):
    win = Zip(*map(lambda i: islice(l, i, None), range(n)))
    ...
7
vaultah
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 contient tous les 5 produits possibles Tuple, puis en utilisant reduce pour imiter la fonction max, nous trouvons le maximum parmi les produits.

7
Abhijith Asokan

Vous pouvez faire ce qui suit:

  • Pour chaque index de début dans range(0, len(L) - 5)
  • Mappez l'index au tuple de start et au produit des éléments L[start:start + 5]
  • Réduire les n-uplets à celui qui a le produit le plus élevé
  • Obtenir la première valeur du tuple résultant = l'index de départ des 5 éléments ayant le produit le plus élevé
  • Renvoie la tranche L[result:result + 5]

Cet algorithme pourrait être encore amélioré pour éviter de re-calculer les sous-produits, mais utilisez un "produit glissant", mis à jour à mesure que vous réduisez de gauche à droite, divisé par l'élément supprimé et multiplié par le nouvel élément. ajoutée.

2
janos

voulez un liner utilisant max et sans max essayez ceci

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
Argus Malware

Le paradigme impératif est souvent:

 state = state0
 while condition:
   # change state 

C'est la manière "naturelle" de programmer pour beaucoup de gens et vous savez comment procéder de cette façon.

Le paradigme pur fonctionnel interdit les variables, qui présentent certains avantages. Il fonctionne avec des fonctions qui communiquent via des paramètres (IN) et des valeurs de retour (OUT). Il utilise fréquemment des fonctions récursives.

Un schéma générique fonctionnel récursif est: 

f = lambda *args : result(*args) if  condition(*args) else f(*newparams(*args))   

Ici, nous pouvons trouver une solution avec (l,i,imax,prodmax) en tant que paramètres et:

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]) 

Aucune autre que les fonctions ont été définies.

Vous pouvez même ne définir aucune fonction pour cela, voir ici par exemple, mais la lisibilité en souffre encore plus. 

Courir :

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

Python limite cette approche en définissant la profondeur récursive sur 2000 et à partir de Python 3, en masquant les outils fonctionnels dans le module functools

0
B. M.

Cette solution utilise reduce pour calculer un produit à 5 valeurs, la compréhension de la liste pour générer tous ces produits, la création de tuples pour avoir l'index correspondant à chacun, reduce pour obtenir le meilleur Tuple.

Un opérateur if else est utilisé pour intercepter le cas où il n'y a pas 5 valeurs dans l'entrée. 

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)

La sortie pour l'exemple d'appel est:

(7, 48)
0
trincot

Une solution Pure Python utilisant recursion 

Tout d'abord, nous devons créer une recursivefunction pour trouver la product d'une list:

def product(l, i=0, s=1):
    s *= l[i]
    if i+1 < len(l):
        return product(l, i+1, s)
    return s

que nous pouvons faire des tests pour:

>>> product([1, 2, 3])
6
>>> product([1, 1, 1])
3
>>> product([2, 2, 2])
8

Ensuite, nous pouvons utiliser cette function dans une autre recursivefunction pour résoudre votre problème:

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

qui fonctionne!

Voici quelques tests pour montrer qu'il fonctionne:

>>> 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
Joe Iddon

Voici une solution Haskell purement fonctionnelle:

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]

Voici ce qu'il fait:

  • À partir de la dernière ligne, il calcule les produits consécutifs à partir de cette liste.
  • tails xs donne tous les sous-ensembles commençant par différentes valeurs de départ:

    > 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],[]]
    
  • De ces queues, nous ne prenons que ceux qui ont au moins 5 éléments de long.
  • Ensuite, nous leur Zip avec des nombres naturels tels que l’index de départ y soit associé.
  • Dans chacun des sous-ensembles, nous prenons les cinq premiers éléments.
  • Ces cinq éléments sont passés à la fonction multiply. Là, ceux-ci sont réduits à un seul numéro, le produit.
  • Après cela, nous revenons à la dernière ligne, nous trions la liste en fonction de la valeur du produit en descendant.
  • Dans la liste résultante, nous ne prenons que le premier élément.
  • Et puis nous imprimons le résultat, qui est (5,450) pour mes données d'entrée.
0
Martin Ueding