在第一次出现元素时拆分列表

Dav*_*era 3 haskell

我想知道是否有一个函数可以让我在第一次出现元素时拆分列表,不包括该元素.基本上,假设:

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在列表中后才会被调用,因此在不存在时处理它并不是必需的.我感谢您的帮助

dfe*_*uer 7

您已提交错误的结果类型,这会阻止类型检查器尽可能地帮助您.你说你想要的

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版本也有这个潜在的问题,但它通过更有用来弥补它.

一旦您提交了其中一个选项,您可能会发现更容易实现正确的实施.


dup*_*ode 6

由于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值上使用它,看看会发生什么.)

  • 在这些类型的工作中,我发现`(id***drop 1)比`fmap`更清晰. (2认同)