Reputation: 75
I need to make something like this:
func ["a","bb","c","aa","bb","c"] ⟼
[("a",[0]), ("bb",[1,4]),("c",[2,5]),("aa",3)]
with this function:
func :: [String] -> [(String, [Int])]
I was thinking something like this:
func :: [String] -> [(String, [Int])]
func (xs) = func1 (reverse xs)
where
func1 [] = []
func1 (x:xs)
| notElem x xs = func1 (xs) ++ [(x, [0])]
| otherwise = func1 (xs)
0 is just a placeholder, how can I put the indices in that position?
Upvotes: 0
Views: 97
Reputation:
I don't know if this will help but this was what I did to solve the problem
zipPos :: [String] -> [(String, Int)]
zipPos xs = zip xs [0..]
singleHead :: ([String], [Int]) -> (String, [Int])
singleHead (x,y) = (head x, y)
filterFstTuple :: (String -> String -> Bool) -> [(String, Int)] -> [(String, Int)]
filterFstTuple _ [] = []
filterFstTuple con xss@(x:_) = filter (con (fst x).fst) xss
getPos :: [(String, Int)] -> [(String, [Int])]
getPos [] = []
getPos xss = singleHead (unzip (filterFstTuple (==) xss)) : getPos (filterFstTuple (/=) xss)
main :: IO()
main = print . getPos $ zipPos ["a", "b", "c", "c", "d", "a"]
Upvotes: 0
Reputation: 531055
Here's an example of how to use Data.Map
to solve this. (I'm not sure if there's a better way to handle the zipWith
.)
import Data.Map (Map)
import qualified Data.Map as Map
func :: [String] -> [(String, [Int])]
func xs = Map.toList . -- [("a", [0]), ("bb", [1,4]), ...]
(Map.map reverse) . -- fromList [("a", [0]), ("bb", [1,4]), ...]
(Map.fromListWith (++)) $ -- fromList [("a", [0]), ("bb", [4,1]), ...]
zipWith (\c i -> (c, [i])) xs [0..] -- [("a", [0]), ("bb", [1]), ...]
This starts with a list of tuples pairing each string to a singleton list of its position in the input, then builds a map where each key is mapped to an accumulated list of positions. The accumulated positions are built up in reverse order, which Map.map reverse
fixes, then the desired list is extracted from the map.
Here is an optimized version, courtesy of dfeuer.
func = map (\(a,b) -> (a, reverse b)) .
Map.toList .
Map.fromListWith (++) .
zipWith (\i c -> (c, [i])) [0..]
Upvotes: 1
Reputation: 4984
In order to have the index, your helper function just needs an extra parameter that you pass a 0
to initially and increment at each recursive call. You may have to change when you call reverse
in order to get the indices in the right order, though!
A second part you'll have to consider is the best way to manage the list of pairs you're creating as output. Lists of pairs like this are sometimes called "association lists" and there is a lookup
function in the Prelude that you can use to get the value associated with a key in such a structure. You might study that function and write a update
helper to go with it in order to update the value at an existing key.
There is another general approach to problems, however, which @Chad Gilbert is hinting at in his answer. Instead of using recursion directly, you can often define your solution as a composition of transformation and combining operations over the problem structure. Solutions in this form often combine mapping, filtering, zipping, and folding. I would recommend practicing with both kinds of solutions.
Upvotes: 0
Reputation: 36375
zip [0..] xs
will give you a list of tuples where the first item is the zero-based index and the second item is the string at that index.
Upvotes: 1