我想用字符串过滤字符串。 我想要的是使用删除每个第一个出现的字符。
myFunc :: String -> String -> String
喜欢:
myFunc "dddog" "bigdddddog" = "biddg"
在"dddog"
:3x d,1x o,1x g
在第二个字符串中,它删除了3x d,1x o和1x g
所以输出:biddg
我不能使用过滤器,因为它会删除所有发生的字符。 我用它挣扎了很长时间。
提前致谢:)
答案 0 :(得分:9)
怎么样
Prelude> :m +Data.List
Prelude Data.List> "bigdddddog" \\ "dddog"
"biddg"
答案 1 :(得分:3)
不是最好的解决方案,但您可以更轻松地了解正在发生的事情:
myfunc :: String -> String -> String
myfunc [] xs = xs
myfunc (x:xs) ys = myfunc xs $ remove x ys
where
remove _ [] = []
remove x (y:ys) = if x == y then ys else y : remove x ys
正如您所说,您想要使用警卫。你是说这个吗?
myfunc :: String -> String -> String
myfunc [] xs = xs
myfunc (x:xs) ys = myfunc xs $ remove x ys
remove :: Char -> String -> String
remove _ [] = []
remove x (y:ys)
| x == y = ys
| otherwise = y : remove x ys
答案 2 :(得分:1)
其他一些解决方案似乎没有产生您发布的相同结果。我想我有一个简单的解决方案可以满足您的要求,但我可能会误解您的需求。我在下面的代码中所做的只是通过列表并对列表中的每个元素应用'delete'。它并不完全有效,但它完成了工作。
import Data.List
myFunc (x:xs) ys = myFunc xs (delete x ys)
myFunc [] ys = ys
可能有更高效的解决方案,例如在树中存储“删除”列表,其中存储的数量作为值存储,然后遍历主列表测试以查看该键的计数是否仍然大于零。我认为这会给你O(n * lg(m))(其中n是要删除的列表的大小,m是“要删除”列表的大小)而不是O(n * m)as就是上面的情况。我认为这个版本也可能是女仆懒惰。
编辑:
这是我使用Data.Map进行讨论的树版本。它有点复杂,但对于大型列表应该更有效,而且有点懒惰
myFunc l ys = myFunc' (makeCount l) ys
where makeCount xs = foldr increment (Map.fromList []) xs
increment x a = Map.insertWith (+) x 1 a
decrement x a = Map.insertWith (flip (-)) x 1 a
getCount x a = case Map.lookup x a of
Just c -> c
Nothing -> 0
myFunc' counts (x:xs) = if (getCount x counts) > 0
then myFunc' (decrement x counts) xs
else x : myFunc' counts xs
myFunc' _ [] = []
答案 3 :(得分:0)
我不太确定你希望你的功能如何表现,这个怎么样?
import Data.List (isPrefixOf)
myFunc :: String -> String -> String
myFunc _ [] = []
myFunc y x'@(x:xs) | y `isPrefixOf` x' = drop (length y) x'
| otherwise = x : myFilter xs y
这在GHCi中给出了以下输出:
> myFunc "dddog" "bigdddddog"
> "bigdd"
如果这不是您的想法,请提供另一个输入/输出示例。
答案 4 :(得分:0)
使用Data.List中的预定义函数,
-- mapAccumL :: (acc -> x -> (acc, y)) -> acc -> [x] -> (acc, [y])
-- lookup :: (Eq a) => a -> [(a, b)] -> Maybe b
{-# LANGUAGE PatternGuards #-}
import Data.List
picks [] = [] -- http://stackoverflow.com/a/9889702/849891
picks (x:xs) = (x,xs) : [ (y,x:ys) | (y,ys) <- picks xs]
myFunc a b = concat . snd $ mapAccumL f (picks a) b
where
f acc x | Just r <- lookup x acc = (picks r,[])
f acc x = (acc,[x])
测试:
Prelude Data.List> myFunc "dddog" "bigdddddog"
"biddg"
编辑:这当然比(\\)
复杂一点。我会把它作为一个例子。它可能还有一些优点,因为它不会反复复制第二个(更长的?)字符串,对于第一个(较短)字符串中的每个非匹配字符,如delete
显然所用,在(\\) = foldl (flip delete)
。
答案 5 :(得分:0)
我喜欢kaan的优雅解决方案。如果你的意思是......这里的“ddd”只有在整体匹配时才会删除:
import Data.List (group,isPrefixOf,delete)
f needles str = g (group needles) str where
g needles [] = []
g needles xxs@(x:xs)
| null needle' = [x] ++ g needles xs
| otherwise = let needle = head needle'
in g (delete needle needles) (drop (length needle) xxs)
where needle' = dropWhile (not . flip isPrefixOf xxs) needles
输出:
*Main> f "dddog" "bigdddddog"
"biddg"
*Main> f "dddog" "bdigdogd"
"bdidgd"
答案 6 :(得分:0)
还没有monadic解决方案,你去了:
import Control.Monad.State
myFunc :: String -> State String String
myFunc [] = return ""
myFunc (x:xs) = get >>= f where
f [] = return (x:xs)
f (y:ys) = if y == x then put ys >> myFunc xs
else myFunc xs >>= return . (x:)
main = do
let (a,b) = runState (myFunc "bigdddddog") "dddog" in
putStr a