gskn13
gskn13

Reputation: 51

How can I sum every 2 elements in a list?

Essentially, I want to perform the following operation: [1, 2, 3, 4, 5, 6, 7] -> [3, 7, 11, 7]

In the above example, the element at the end of the list is left alone as there is nothing it can be added with since the list is odd in length.

I wanted to turn the list into a list of tuples such as [1, 2, 3, 4] -> [(1,2),(3,4)] then perform the addition on each tuple, but I could not figure out how to do that, and wasn't sure it would work with an odd length list.

Surely there is a way to add every two elements in a list.

Upvotes: 1

Views: 512

Answers (3)

Elmex80s
Elmex80s

Reputation: 3504

Very short

map sum . chunksOf 2

Upvotes: 0

Izaak Weiss
Izaak Weiss

Reputation: 1310

One simple way to do this is via a basic recursive definition:

sumPairs :: Num a => [a] -> [a]
-- first, we deal with the base case
sumPairs [] = []
-- next we deal with the odd length list base case
sumPairs [x] = [x]
-- now we can recurse!
sumPairs (x:y:list) = (x+y) : sumPairs list

However, if you want to do this by combining existing functions, you can search hoogle for [a] -> [(a,a)] (https://hoogle.haskell.org/?hoogle=%5Ba%5D+-%3E+%5B%28a%2Ca%29%5D&scope=set%3Astackage) to see if there are any relevant functions.

Unfortunately, it doesn't appear as if there are any. Some functions you could write, if you wanted something more compositional, are:

pairUp :: Num a => [a] -> [(a,a)]
pairUp [] = []
pairUp [x] = [(x, 0)]
pairUp (x:y:list) = (x,y) : pairUp list

sumPairs :: Num a => [a] -> [a]
sumPairs = map (uncurry (+)) . pairUp

Or, if you wanted to be even more generic

pairUp :: Monoid a => [a] -> [(a,a)]
pairUp [] = []
pairUp [x] = [(x, mempty)]
pairUp (x:y:list) = (x,y) : pairUp list

mergePairs :: Monoid a => [a] -> [a]
mergePairs = map (uncurry (<>)) . pairUp

and then

sumPairs :: Num a => [a] -> [a]
sumPairs = map getSum . mergePairs . map Sum

Or even

combinePairs :: (a -> a -> a) -> [a] -> [a]
combinePairs _ [] = []
combinePairs _ [x] = [x]
combinePairs _ (x:y:list) = f x y : combinePairs list

sumPairs :: Num a => [a] -> [a]
sumPairs = combinePairs (+)

Upvotes: 1

For this problem, I think I'd fall back to explicit recursion:

sumPairs :: Num a => [a] -> [a]
sumPairs (x:y:ys) = x+y:sumPairs ys
sumPairs xs = xs

Nice and simple: if there's at least two elements, add them up then recurse to do the rest. Otherwise (meaning there's zero or one element), just return the same list you got.

Upvotes: 0

Related Questions