我想知道是否有一个函数可以让我在第一次出现元素时拆分列表,不包括该元素.基本上,假设:
listT= [1,3,2,5,6,3,2,6]
Run Code Online (Sandbox Code Playgroud)
那么我想定义(或者不是,如果它已经存在),一个函数splitAtFirst这样
splitAtFirst 2 listT = [[1,3],[5,6,3,2,6]]
Run Code Online (Sandbox Code Playgroud)
到目前为止我的尝试看起来像这样:
splitAtfirst::(Eq a)=> a->[a]->[[a]]
splitAtfirst _ []=[]
splitAtfirst a (x:xs)
|a==x = [xs]
|otherwise = [x]: splitAtfirst a (xs)
Run Code Online (Sandbox Code Playgroud)
但是,我明白了
>splitAtfirst 2 [1,3,2,5,6,3,2,6]
>[[1],[3],[5,6,3,2,6]]
Run Code Online (Sandbox Code Playgroud)
我知道问题发生的原因,但到目前为止我还没有找到一个好的解决方案
我感谢任何帮助!
编辑:这是一个辅助函数,只有在检查elem在列表中后才会被调用,因此在不存在时处理它并不是必需的.我感谢您的帮助
您已提交错误的结果类型,这会阻止类型检查器尽可能地帮助您.你说你想要的
splitAtFirst 2 listT = [[1,3],[5,6,3,2,6]]
Run Code Online (Sandbox Code Playgroud)
这会引导你
splitAtfirst::(Eq a)=> a->[a]->[[a]]
Run Code Online (Sandbox Code Playgroud)
这允许将列表拆分成任意多个列表.
但实际上你想将列表分成两部分.在你的问题中你没有提到的一点是你想要的结果是什么,如果我问这样的东西splitAtFirst 2 [1,3],在哪里找不到元素.有三种选择似乎合理:
splitAtFirst :: Eq a => a -> [a] -> Maybe ([a],[a])
-- splitAtFirst 2 [1,3] = Nothing
splitAtFirst :: Eq a => a -> [a] -> ([a],[a])
-- splitAtFirst 2 [1,3] = ([1,3],[])
splitAtFirst :: Eq a => a -> [a] -> ([a], Maybe [a])
-- splitAtFirst 2 [1,3] = ([1,3],Nothing)
Run Code Online (Sandbox Code Playgroud)
请注意,我没有建议
-- splitAtFirst 2 [1,3] = ([], [1,3])
Run Code Online (Sandbox Code Playgroud)
原因与懒惰和效率有关 - 你能弄明白为什么吗?第一个Maybe版本也有这个潜在的问题,但它通过更有用来弥补它.
一旦您提交了其中一个选项,您可能会发现更容易实现正确的实施.
由于dfeuer已经指出了修复实现的方法,我将简单介绍现成的解决方案:
splitAtFirst :: Eq a => a -> [a] -> ([a], [a])
splitAtFirst x = fmap (drop 1) . break (x ==)
Run Code Online (Sandbox Code Playgroud)
这splitAtFirst实现了dfeuer答案中三个建议的第二个选项.关于每个组件的几点说明:
(x ==)是一个测试相等的函数x,返回a Bool.
break使用布尔测试(此处(x ==))将列表分成两部分,第二个列表以通过测试的第一个元素开头.这两个列表作为一对返回(请参阅dfeuer的答案,原因是这样).
drop 1 如果列表的第一个元素不为空,则删除该列表的第一个元素(如果列表为空,则将其单独留下).
fmap需要花费相当长的时间才能正确解释,所以我只想说fmap f应用于一对(例如结果break)将函数应用于该f对的第二个元素.在我们的例子中,fmap (drop 1)将删除第二个列表的第一个元素 - 即分隔符.(要了解更多信息fmap,请搜索关键字"functor",或者只是尝试在列表或Maybe值上使用它,看看会发生什么.)