我想要一个带有签名takeUntill
的函数takeUntill :: (Int -> Bool) -> [Int] -> [Int]
。我确实实现了该实现,但是我正在寻找一种比现有问题更干净的解决方案。
我当前的解决方案是:
takeUntill :: (Int -> Bool) -> [Int] -> [Int]
takeUntill p a = snd $ maximum $ [(length x, x) | x <- groups p a]
groups :: (Int -> Bool) -> [Int] -> [[Int]]
groups _ [] = []
groups p a = ((takeWhile p a):(groups p (drop 1 $ dropWhile p a)))
答案 0 :(得分:3)
我认为您执行此操作的方式看起来不错,但是groups
函数很杂乱-特别是您在每一步中从不满足p的元素中精确地删除1的方式,这可能会导致结果里面有很多多余的空列表。 (只要takeUntil
的至少1个元素满足a
,这些当然不会影响p
,但它们仍然存在。)
我将使用一些有用的库函数按如下方式重写groups
:
groups p a = filter (p . head) $ groupBy ((==) `on` p) a
我不知道它是否更有效,但是我当然觉得它更容易阅读。为了提供一些解释,groupBy
(http://hackage.haskell.org/package/base-4.12.0.0/docs/Data-List.html#v:groupBy)来自Data.List
,并根据两个连续参数的函数是否为真将列表分为子列表列表。 on
(http://hackage.haskell.org/package/base-4.12.0.0/docs/Data-Function.html#v:on)是Data.Function
中一个方便的小函数,它将另一个函数的结果馈入二进制函数的输入。结果是
groupBy ((==) `on` p) a
将列表分为几部分,其中p
始终为True
或始终为False
。然后,我们将其过滤为真实的部分。