Reputation: 3
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
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
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