BlueSnow
BlueSnow

Reputation: 3

Counting number of occurences of ints in a list

I'm trying to do the following:
The function I'm writing takes list of tuples of ints [(x,y),(i,j)...] in range 0-6
I want to return an [Int] where each element is a count of how many of its respective number were seen in the list.
e.g. [(0,1), (1,2), (2,3)] would return [1, 2, 2, 1, 0, 0, 0].

in other words, one 0, two 1's, two 2's 1 three and no 4s, 5s or 6s

countNumbers :: [(Int, Int)] -> [Int]  
countNumbers [] = [0, 0, 0, 0, 0, 0, 0]

but am not sure how to go about this as I am somewhat new to Haskell.
EDIT - I've found a solution - please let me know if there's a more succinct way to code it !

type ProbabilityMatrix = (Int,Int,Int,Int,Int,Int,Int)
-- converts list of tuples into list of ints as suggested
tupleToList :: [(Int, Int)] -> [Int]  
tupleToList ((a,b):xs) = a : b : tupleToList xs  
tupleToList _          = []    

tupleToList2 :: [Int] -> ProbabilityMatrix -> ProbabilityMatrix  
tupleToList2 [] list = list  
tupleToList2 (x : xs) (zero, one, two, three, four, five, six)  
  | x == 0 =  tupleToList2 xs (zero + 1, one, two, three, four, five, six)  
  | x == 1 = tupleToList2 xs (zero, one + 1, two, three, four, five, six)  
  | x == 2 = tupleToList2 xs (zero, one, two + 1, three, four, five, six)  
  | x == 3 = tupleToList2 xs (zero, one, two, three + 1, four, five, six)  
  | x == 4 = tupleToList2 xs (zero, one, two, three, four + 1, five, six)  
  | x == 5 = tupleToList2 xs (zero, one, two, three, four, five + 1, six)  
  | x == 6 = tupleToList2 xs (zero, one, two, three, four, five, six + 1)  
  | otherwise = tupleToList2 xs (zero + 1, one, two, three, four, five, six)   

Upvotes: 0

Views: 887

Answers (2)

RoadRunner
RoadRunner

Reputation: 26315

You can try this solution:

-- flattens a list of tuples into a list
flatten :: (Num a) => [(a, a)] -> [a]
flatten xs = concat [[a,b] | (a, b) <- xs]

-- updates list element at a position
update_list :: (Num a) => Int -> [a] -> [a]
update_list n xs = take n xs ++ [(xs !! n) + 1] ++ drop (n + 1) xs

-- performs count of numbers
count_numbers :: [(Int, Int)] -> [Int]
count_numbers xs = go (flatten xs) acc
    where go [] acc = acc
          go (x:xs) acc = go xs (update_list x acc)
          acc = replicate 7 0

Where it first flattens a list:

*Main> flatten [(0,1), (1,2), (2,3)]
[0,1,1,2,2,3]

Then updates a list at a certain position:

*Main> update_list 1 (replicate 7 0)
[0,1,0,0,0,0,0]

And performs counting of list elements similarly to your function tupleToList2, where an accumulator of the number counts is stored and updated:

*Main> count_numbers [(0,1), (1,2), (2,3)]
[1,2,2,1,0,0,0]
*Main> count_numbers [(0,1), (1,2), (2,4)]
[1,2,2,0,1,0,0]
*Main> count_numbers [(0,0), (1,0), (3,6)]
[3,1,0,1,0,0,1]

Upvotes: 0

Glubus
Glubus

Reputation: 2855

How about you create the result list of Ints for each tuple, and then merge them together with a Sum function. You'd need at least two functions with signatures:

tupleToList :: (Int, Int) -> [Int]

and

sumLists :: [Int] -> [Int] -> [Int]

The first one will detect both items in the tuple, and generate the corresponding list for it, e.g. tupleToList (4, 2) -> [0,0,1,0,1,0,0].

The second function will merge two lists of ints by summing 2 counters at the same index, e.g. sumLists [0,1,1,0,1] [1,1,0,0,0] -> [1,2,1,0,1]. You can do this recursively until you end up with 1 list that will be the answer to the problem.

You'd execute tupleToList for each of the elements in the tuple list (probably with map) and then consolidate the resulting list by executing sumLists for 2 lists iteratively (maybe with foldl)

This approach is rather naive and would probably run slowly for bigger inputs.

Upvotes: 3

Related Questions