我正在尝试在Haskell中创建一个函数,将字符串拆分为某个字符串和一个特定数字的列表。
为了做到这一点,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])
这就是我在元组左侧的5所需要的东西。 但现在我想用char和字符串来做这件事。但是splitAt只接受第二个参数的int和int。我想要
splitAt 'c' "abcde"
导致
("abc", "de")
我正朝着
的方向寻找一些东西splitAt (findIndex 'c' "abcde") "abcde"
但是函数findIndex返回类似Maybe Int的东西,而splitAt需要一个Int。然后我尝试了以下
splitAt (head (findIndices (== 'c') "abcde")) "abcde"
这是一种可能的解决方案,但它会返回以下内容
("ab","cde")
将c放在tupple的错误一侧。您可以将succ添加到c,但如果char是Z,那么结果会是什么。
是否有一种简单的方法可以修改
splitAt (findIndex 'c' "abcde") "abcde"
工作?
谢谢!
答案 0 :(得分: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])
答案 1 :(得分:2)
您可以使用fromMaybe
函数从Maybe获取结果,例如:
splitlist = splitAt (fromMaybe 0 (findIndex 'c' "abcde") "abcde")
fromMaybe :: a - >也许是 - >一个强>
fromMaybe函数采用默认值和Maybe值。如果 Maybe is Nothing,它返回默认值;否则,它 返回Maybe中包含的值。 (source)。
如果您的findIndex返回Nothing
,则splitAt的结果将为("",list)
,对于相同的情况,但默认值设置为length list
,最终结果它将是(list,"")
。
答案 2 :(得分:1)
鉴于c :: Char
和s :: String
,您可以将其写为
splitAt ((1+) $ fromJust $ findIndex (==c) s) s
但
c
未加入s
s
两次 Maybe
替代方案是
maybe Nothing (\x -> splitAt (1+x) s) (findIndex (==c) s)
你可以在我的例子中设置“else value”(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, "")
中没有c
,则会s
。
答案 3 :(得分: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)
这是如何运作的:
zip
)。每对中的第一个元素取自原始列表。该对的第二个元素是Bool
,表明列表中的 previous 元素是否是我们正在寻找的元素。这就是为什么我们说False : map p xs
---如果我们只是说map p xs
,我们会完全重现break
的行为。在开始时坚持额外的False
是重要的一点。break
。我们的条件编码在每对的第二个元素中。Bool
个。我们不再需要它们了。