2012-12-09 66 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。我們不再需要它們了。