2012-12-09 38 views
2

我想在Haskell中将某个字符串拆分为某个字符和某个列表中的某个数字。用字符或int拆分字符串/列表

为了做到这一点,splitAt函数正是我需要的数字,但我不能给这个函数的字符。

E.g.

splitAt 5 [1,2,3,4,5,6,7,8,9,10] 

([1,2,3,4,5],[6,7,8,9,10]) 

是execlty我在元组的左侧与所需的5。 但现在我想用char和一个字符串来做到这一点。但splitAt只接受和int为第二个参数。我想

splitAt 'c' "abcde" 

导致

("abc", "de") 

我找的东西在

splitAt (findIndex 'c' "abcde") "abcde" 

方向,但findIndex返回类型的东西的功能也许INT和splitAt需要一个诠释。然后我尝试以下

splitAt (head (findIndices (== 'c') "abcde")) "abcde" 

这是一个可能的解决方案,但它的元组的错误一边的C返回以下

("ab","cde") 

。您可以添加SUCC到c但结果是什么,如果炭是Z ..

有一种简单的方法来修改,使

splitAt (findIndex 'c' "abcde") "abcde" 

工作?

谢谢!

+2

如果您使用['break'](http://hackage.haskell.org/packages/archive/base/latest/doc/html/Prelude.html#v:break)'::(a - > Bool) - > [a] - >([a],[a])'而不是'splitAt',则不需要'findIndex'。 –

+0

@SebastianPaaskeTørholm,但你在右边而不是在左边得到'c'。 – AndrewC

回答

2

您可以使用findIndex,只是解开了Maybe并添加一个:

import Data.List 

splitAfter :: (a-> Bool) -> [a] -> ([a],[a]) 
splitAfter this xs = case findIndex this xs of 
    Nothing -> (xs,[]) 
    Just n -> splitAt (n+1) xs 

捐赠,例如

*Main> splitAfter (=='c') "abcde" 
("abc","de") 

也许是对的方式,很容易恢复编码失败方便的数据类型。甚至还有一个功能maybe :: b -> (a -> b) -> Maybe a -> b使用默认值和功能分别处理两种情况:

splitAfter' :: (a-> Bool) -> [a] -> ([a],[a]) 
splitAfter' this xs = maybe (xs,[]) 
        (\n -> splitAt (n+1) xs) 
        (findIndex this xs) 

也可以工作。例如

*Main> splitAfter' (==5) [1..10] 
([1,2,3,4,5],[6,7,8,9,10]) 
+0

正是我需要的,thx! –

2

可以使用fromMaybe功能,拍摄效果从也许,例如:

splitlist = splitAt (fromMaybe 0 (findIndex 'c' "abcde") "abcde") 

fromMaybe :: A - >也许 - >一

fromMaybe函数采用默认值和Maybe值。如果 Maybe为Nothing,则返回默认值;否则,它 返回Maybe中包含的值。 (source)。

设置为0,如果你的findIndex返回Nothing默认值splitAt的结果将是("",list),对于相同的情况下,但设置为length list默认值的最终结果将是(list,"")

1

鉴于c :: Chars :: String,你可以写一些作为

splitAt ((1+) $ fromJust $ findIndex (==c) s) s 

  1. 你会得到一个异常,如果c不进s
  2. 你穿越s两次

Maybe选择是

maybe Nothing (\x -> splitAt (1+x) s) (findIndex (==c) s) 

可以设置“其他值”(在我的例子Nothing)。

您可以编写自己的功能

splitAt' :: Char -> String -> (String, String) 
splitAt' _ [] = ("", "") 
splitAt' c (x:xs) | c == x = ([c], xs) 
        | True = (x:cs, ys) where (cs, ys) = splitAt' c xs 

然后,你会得到(s, "")如果不是cs

0

这里有一个不同的方式,不涉及与列表索引混乱。

break几乎是你想要的。让我们重复使用它。您希望将匹配元素包含在第一个输出列表的末尾,而不是在第二个输出列表的开头。

import Control.Arrow ((***)) 

breakAfter :: (a -> Bool) -> [a] -> ([a], [a]) 
breakAfter p xs = map fst *** map fst $ break snd (zip xs $ False : map p xs) 

这是如何工作:

  1. 将我们的输入列表进入对(zip)的列表。每对中的第一个元素来自原始列表。该对中的第二个元素是Bool,说明列表中的以前的元素是否是我们正在寻找的元素。这就是为什么我们说False : map p xs ---如果我们只是说map p xs,我们会重现break的行为。重要的是,在开始时坚持额外的False
  2. 重用break。我们的条件编码在每一对的第二个元素中。
  3. 丢掉所有那些Bool s。我们不再需要它们了。