Haskell过滤字符串只有第一个出现的Char

时间:2013-07-15 20:57:47

标签: haskell

我想用字符串过滤字符串。 我想要的是使用删除每个第一个出现的字符。

myFunc :: String -> String -> String

喜欢:

myFunc "dddog" "bigdddddog" = "biddg"

"dddog":3x d,1x o,1x g

在第二个字符串中,它删除了3x d,1x o和1x g 所以输出:biddg

我不能使用过滤器,因为它会删除所有发生的字符。 我用它挣扎了很长时间。

提前致谢:)

7 个答案:

答案 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