There are several ways to solve this problem, and Adam has already given you an efficient map-based method. However, I think that a solution using only lists and recursion would also be instructive, especially when learning Haskell. Since you already received the answer, I hope I can write a solution here without messing up anything.
The way I approached this is to think about how we can reduce the input list in the output list. Start with
[('A',3), ('B',2), ('C',2), ('A',5), ('C',3), ('C',2)]
The goal is to end the list of results, where each tuple begins with a unique character. Building such a list of results can be done gradually: start with an empty list, and then insert tuples into the list, making sure that you do not duplicate characters. Type will be
insertInResult :: (Char, Integer) -> [(Char, Integer)] -> [(Char, Integer)]
It takes a pair, for example ('A',3) , and inserts it into the existing list of unique pairs. The result is a new list of unique pairs. This can be done as follows:
insertInResult (c, n) [] = [(c, n)] insertInResult (c, n) ((c', n'):results) | c == c' = (c, n + n') : results | otherwise = (c', n') : (insertInResult (c, n) results)
Explanation: inserting a tuple into an empty result list is easy, just insert it. If the list of results is not empty, we will get the first result (c', n') with comparison with the sample. We check to see if the characters match the guard, and add numbers, if so. Otherwise, we simply copy the tuple of the result and paste the tuple (c, n) into the remaining results.
Now we can do
*Main> insertInResult ('A',3) [] [('A',3)] *Main> insertInResult ('B',2) [('A',3)] [('A',3),('B',2)]
The next step is to use insertInResult several times in the input list so that we create a list of results. I called this function sumPairs' , since I called the top-level function sumPairs :
sumPairs' :: [(Char, Integer)] -> [(Char, Integer)] -> [(Char, Integer)] sumPairs' [] results = results sumPairs' (p:pairs) results = sumPairs' pairs (insertInResult p results)
This is a simple function that simply iterates over the first argument and inserts each pair into a list of results. The final step is to call this helper function with an empty list of results:
sumPairs :: [(Char, Integer)] -> [(Char, Integer)] sumPairs pairs = sumPairs' pairs []
It works!: -)
*Main> sumPairs [('A',3), ('B',2), ('C',2), ('A',5), ('C',3), ('C',2)] [('A',8),('B',2),('C',7)]
The complexity of this solution is not as good as that based on Data.Map . For a list with n pairs, we call insertInResult n times from sumPairs' . Each insertInResult call can be repeated up to n times until it finds the corresponding result or reaches the end of the results. This gives a time complexity of O (n²). A solution based on Data.Map will have O (n log n) time complexity since it uses log n time to insert and update each of n elements.
Note that this will be the same complexity you would get if you sorted the input list and then scanned it once to add adjacent tuples with the same character:
sumPairs pairs = sumSorted (sort pairs) [] sumSorted [] result = result sumSorted (p:pairs) [] = sumSorted pairs [p] sumSorted ((c,n) : pairs) ((c',n') : results) | c == c' = sumSorted pairs ((c,n + n') : results) | otherwise = sumSorted pairs ((c,n) : (c',n') : results)