2011-01-19 43 views
11

Escriba una función que devuelva la suma acumulada de la lista. p.ej. corriendo [1,2,3,5] es [1,3,6,11]. Escribo esta función a continuación, que simplemente puede devolver la suma final de todos los valores de la lista. Entonces, ¿cómo puedo separarlos uno por uno?Cálculo de la suma acumulada de la lista en Haskell

sumlist' xx=aux xx 0 
    where aux [] a=a 
      aux (x:xs) a=aux xs (a+x) 

Respuesta

9

Se puede ajustar la función de producir una lista simplemente anteponiendo a+x al resultado de cada paso y utilizando la lista vacía como el caso base:

sumlist' xx = aux xx 0 
    where aux [] a = [] 
      aux (x:xs) a = (a+x) : aux xs (a+x) 

Sin embargo es más idiomático Haskell para expresar este tipo de cosa como un pliegue o escaneo.

25

Creo que quieres una combinación de scanl1 y (+), así que algo como

scanl1 (+) *your list here* 

scanl1 se aplicará la función dada a través de una lista, e informar cada valor intermedio en la lista devuelta.

Al igual que, para escribirlo en pseudo código,

scanl1 (+) [1,2,3] 

emitiría una lista como:

[1, 1 + 2, 1 + 2 + 3] 

o en otras palabras,

[1, 3, 6] 

Learn You A Haskell tiene mucho de grandes ejemplos y descripciones de escaneos, pliegues y mucho más de las golosinas de Haskell.

Espero que esto ayude.

3

Mientras scanl1 es claramente la solución "canónica", todavía es instructivo ver cómo podría hacerlo con foldl:

sumList xs = tail.reverse $ foldl acc [0] xs where 
    acc (y:ys) x = (x+y):y:ys 

O pointfree:

sumList = tail.reverse.foldl acc [0] where 
    acc (y:ys) x = (x+y):y:ys 

Aquí es un bruto fea enfoque de la fuerza:

sumList xs = reverse $ acc $ reverse xs where 
    acc [] = [] 
    acc (x:xs) = (x + sum xs) : acc xs 

Hay una linda (pero no muy eficiente) solución que usa inits:

sumList xs = tail $ map sum $ inits xs 

Una vez más pointfree:

sumList = tail.map sum.inits 
+0

@ sepp2k: ¿Cómo se obtiene la suma de los elementos que quedan si se comienza en el lado derecho de la lista? – Landei

+0

@Lamdei: Lo siento, no estaba pensando bien. Sin embargo, no ser perezoso es una buena razón para no usar foldl (o su enfoque de fuerza bruta). – sepp2k

+1

¿Por qué 'reverse'? 'sumList = (\' snd \ '[]). foldl (\\ (a, k) x -> (a + x, k. (a + x :))) (0, id) 'funciona bien en la dirección de avance. – ephemient

0

relacionada a otra pregunta me encontré con esta forma:

rsum xs = map (\(a,b)->a+b) (zip (0:(rsum xs)) xs) 

creo que es aún bastante eficiente.

Cuestiones relacionadas