2017-03-19 1 views
2

Je souhaite définir une fonction accumulate_n(op, init, sequences) utilisant accumulate(op, init, seq) en tant que tel:définissant accumulate_n? (fonctions d'ordre supérieur)

La fonction accumulate_n(op, init, sequences) est similaire à accumulate(op, init, seq) sauf qu'il prend comme troisième argument d'une séquence de séquences de longueur égale. Il applique la fonction d'accumulation op pour combiner tous les premiers éléments des séquences, tous les deuxièmes éléments des séquences, et ainsi de suite, et renvoie une séquence des résultats. Par exemple, si s est une séquence contenant quatre séquences, [[1, 2, 3], [4, 5, 6], [7, 8, 9], [10, 11, 12]], alors la valeur de accumulate_n(lambda x, y: x+y, 0, s) doit être la séquence [22, 26, 30].

def accumulate(op, init, seq): 
    if not seq: 
     return init 
    else: 
     return op(seq[0], accumulate(op, init, seq[1:])) 

def accumulate_n(op, init, sequences): 
    if (not sequences) or (not sequences[0]): 
     return type(sequences)() 
    else: 
     return ([accumulate(op, init, ??)] 
       + accumulate_n(op, init, ??)) 

mais je suis coincé dans la partie ?? que je suis à une perte de ce qu'il faut inclure. Je suppose que je pourrais utiliser la fonction intégrée map, mais encore assez incertain de ce qu'il faut faire.

Voici quelques exemples de ce que la fonction est censé exécuter:

accumulate_n(lambda x,y: x+y, 0, [[1,2],[3,4],[5,6]]) 
# [9, 12] 
accumulate_n(lambda x,y: x+y, 0, [[1,4],[5,7],[9,10]]) 
# [15, 21] 
accumulate_n(lambda x,y: x+y, 0, [[9,8],[7,6],[5,4]]) 
# [21, 18] 

Si quelqu'un pouvait aider, je voudrais vraiment l'apprécier! Je vous remercie!

+0

il me semble que vous pouvez simplement utiliser '' reduce' pour accumulate' ... Notez encore que ce 'accumulate_n' est supposé faire ... –

+0

@ juanpa.arrivillaga désolé pour la question imprécise! juste édité ma question expliquant ce que 'accumulate_n' est supposé faire – elle

Répondre

1

Il semble que vous » cherchez à obtenir:

  • une liste de premier élément de chaque séquence, qui pourrait être [s[0] for s in sequences] et
  • une liste des éléments restants de chaque séquence, qui peut être [s[1:] for s in sequences].

En tout:

def accumulate(op, init, seq): 
    if not seq: 
     return init 
    else: 
     return op(seq[0], accumulate(op, init, seq[1:])) 

def accumulate_n(op, init, sequences): 
    if (not sequences) or (not sequences[0]): 
     return type(sequences)() 
    else: 
     heads = [s[0] for s in sequences] 
     tails = [s[1:] for s in sequences] 

     return ([accumulate(op, init, heads)] 
       + accumulate_n(op, init, tails)) 

mais pour ce que ça vaut, je ferais cette ligne-sage au lieu de sage colonne et requiers init être une séquence elle-même:

def accumulate_n_(op, init, sequences): 
    try: 
     head = next(sequences) 
    except StopIteration: 
     return init 

    return accumulate_n_(
     op, 
     [op(x, y) for x, y in zip(init, head)], 
     sequences, 
    ) 

def accumulate_n(op, init, sequences): 
    return accumulate_n_(op, init, iter(sequences)) 

Cleaner impératif:

def accumulate_n(op, init, sequences): 
    for s in sequences: 
     init = [op(x, y) for x, y in zip(init, s)] 

    return init 

Enfin, avec functools.reduce:

def zipper(op): 
    return lambda xs, ys: [op(x, y) for x, y in zip(xs, ys)] 

def accumulate_n(op, init, sequences): 
    return reduce(zipper(op), sequences, init) 
1

La fonction zip builtin, conjointement avec l'utilisation de * pour décompresser une liste en arguments, est à portée de main pour sélectionner la valeur nième d'une séquence de séquences:

def accumulate_n(op, init, sequences): 
    if (not sequences) or (not sequences[0]): 
     return type(sequences)() 
    else: 
     return [accumulate(op, init, i) for i in zip(*sequences)]