我需要做这样的事情:
func ["a","bb","c","aa","bb","c"] ⟼
[("a",[0]), ("bb",[1,4]),("c",[2,5]),("aa",3)]
使用此功能:
func :: [String] -> [(String, [Int])]
我在想这样的事情:
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只是占位符,如何将索引置于该位置?
答案 0 :(得分:1)
zip [0..] xs
将为您提供元组列表,其中第一项是从零开始的索引,第二项是该索引处的字符串。
答案 1 :(得分:1)
以下是如何使用Data.Map
解决此问题的示例。 (我不确定是否有更好的方法来处理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]), ...]
这首先是一个元组列表,它将每个字符串与输入中其位置的单例列表配对,然后构建一个映射,其中每个键映射到一个累积的位置列表。累积的位置以相反的顺序构建,Map.map reverse
修复,然后从地图中提取所需的列表。
这是一个优化版本,由dfeuer提供。
func = map (\(a,b) -> (a, reverse b)) .
Map.toList .
Map.fromListWith (++) .
zipWith (\i c -> (c, [i])) [0..]
答案 2 :(得分:0)
为了获得索引,你的辅助函数只需要一个额外的参数,你将0
传递给最初并在每次递归调用时递增。您可能必须在致电reverse
时更改,以便以正确的顺序获取索引!
您必须考虑的第二部分是管理您作为输出创建的对列表的最佳方式。像这样的对的列表有时被称为"关联列表"并且Prelude中有一个lookup
函数,您可以使用它来获取与此类结构中的键关联的值。您可以研究该函数并编写update
帮助程序,以便更新现有密钥的值。
答案 3 :(得分:0)
我不知道这是否会有所帮助,但这就是我解决问题的方法
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"]