Haskell在最后一次出现时分裂了字符串

时间:2016-10-13 20:33:15

标签: list haskell split

有没有什么办法可以将最后一次出现给定角色的Haskell中的String拆分成2个列表? 例如,我想拆分列表" a b c d e"在太空中(" a b c d"," e")。 谢谢你的回答。

5 个答案:

答案 0 :(得分:5)

我不确定为什么建议的解决方案如此复杂。只需 一次两次遍历

splitLast :: Eq a => a -> [a] -> Either [a] ([a],[a])
splitLast c' = foldr go (Left [])
    where
        go c (Right (f,b)) = Right (c:f,b)
        go c (Left s) | c' == c = Right ([],s)
                      | otherwise = Left (c:s)

请注意,这是总计,并清楚地表明其失败。如果无法进行拆分(因为字符串中指定的字符不是),则会返回带有原始列表的Left。否则,它将返回带有两个组件的Right

ghci> splitLast ' ' "hello beautiful world"
Right ("hello beautiful","world")
ghci> splitLast ' ' "nospaceshere!"
Left "nospaceshere!"

答案 1 :(得分:2)

它不漂亮,但它有效:

import Data.List
f :: Char -> String -> (String, String)
f char str = let n = findIndex (==char) (reverse str) in
                case n of
                  Nothing -> (str, [])
                  Just n  -> splitAt (length str - n -1) str

我的意思是f 'e' "a b c d e" = ("a b c d ", "e"),但我自己不会裁掉这个尾随空间。

答案 2 :(得分:2)

我会选择更多模式匹配。

import Data.List

splitLast = contract . words
    where contract [] = ("", "")
          contract [x] = (x, "")
          contract [x,y] = (x, y)
          contract (x:y:rest) = contract $ intercalate " " [x,y] : rest  

对于长列表,我们只使用空格加入前两个字符串并再次尝试较短的列表。一旦长度减少到2,我们就会返回这对字符串。

对于没有空格的字符串,

(x, "")似乎是一个合理的选择,但我想你可以返回("", x)

不清楚("", "")是空字符串的最佳选择,但它似乎是提出错误或将返回类型更改为Maybe (String, String)之类的合理替代方法。

答案 3 :(得分:1)

我可以提出以下解决方案:

splitLast list elem = (reverse $ snd reversedSplit, reverse $ fst reversedSplit)
  where 
  reversedSplit = span (/= elem) $ reverse list

可能不是最快的(两个不必要的反转),但我喜欢它的简单性。

如果你坚持要删除我们分裂的空间,你可以去:

import qualified Data.List as List
splitLast list elem = splitAt (last $ List.elemIndices elem list) list

但是,此版本假定至少有一个元素与模式匹配。如果你不喜欢这个假设,代码会稍长一些(但这里没有双重反转):

import qualified Data.List as List
splitLast list elem = splitAt index list where
    index = if null indices then 0 else last indices
    indices = List.elemIndices elem list

当然,在开始时选择拆分是任意的,最后拆分可能会更加直观 - 然后您只需将0替换为length list

答案 4 :(得分:1)

我的想法是在每次出现时拆分,然后将初始部分与最后一部分分开。

尖头:

import Control.Arrow   -- (&&&)
import Data.List       -- intercalate
import Data.List.Split -- splitOn
breakOnLast :: Eq a => a -> [a] -> ([a], [a])
breakOnLast x = (intercalate x . init &&& last) . splitOn x

点免费:

liftA2 (.) ((&&& last) . (. init) . intercalate) splitOn

(.) <$> ((&&&) <$> ((.) <$> pure init <*> intercalate) <*> pure last) <*> splitOn