2011-01-19 17 views
11

Napisz funkcję, która zwraca bieżącą sumę list. na przykład działa [1,2,3,5] to [1,3,6,11]. Piszę tę funkcję poniżej, po prostu mogę zwrócić ostatnią sumę wszystkich wartości z listy. Jak mogę je rozdzielić jeden po drugim?Suma obliczeniowa sumy w Haskell

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

Odpowiedz

9

Można dostosować swoją funkcję, aby produkować listę, po prostu poprzedzenie a+x do wyniku na każdym kroku i przy użyciu pustą listę, jak w przypadku podstawowej:

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

jednak jest bardziej idiomatyczne Haskell wyrazić tego rodzaju rzeczy jako fałd lub skan.

25

myślę chcesz kombinacji scanl1 i (+), a więc coś takiego

scanl1 (+) *your list here* 

scanl1 zastosuje daną funkcję całej listy, a następnie zgłosić każdą wartość pośrednią do zwracanej listy.

Podobnie jak napisać go w pseudo kod,

scanl1 (+) [1,2,3] 

byłoby wyjście lista jak:

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

lub innymi słowy,

[1, 3, 6] 

Learn You A Haskell ma wiele świetnych przykładów i opisów skanów, fałd i wiele innych gadżetów Haskella.

Mam nadzieję, że to pomoże.

3

Podczas scanl1 jest oczywiście rozwiązanie "kanoniczne", nadal jest pouczające, aby zobaczyć, jak można to zrobić z foldl:

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

Or pointfree:

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

Oto brzydki bydlę Wymuś podejście:

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

Istnieje urocze (ale nie bardzo wydajne) rozwiązanie z wykorzystaniem inits:

sumList xs = tail $ map sum $ inits xs 

Ponownie pointfree:

sumList = tail.map sum.inits 
+0

@ sepp2k: Jak uzyskać sumę elementów w lewo, jeśli zaczynasz od prawej strony listy? – Landei

+0

@Lamdei: Przepraszam, nie myślałem dobrze. Jednak nie jest leniwy jest nadal dobrym powodem, aby nie używać foldl (lub podejście brute force). – sepp2k

+1

Dlaczego "odwrócić"? 'sumList = (\' snd \ '[]). foldl (\\ (a, k) x -> (a + x, k. (a + x :))) (0, id) 'działa dobrze w kierunku do przodu. – ephemient

0

związany z innym pytanie znalazłem w ten sposób:

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

myślę, że to nawet całkiem wydajny.