Haskell takeWhile + 1

时间:2017-01-19 12:20:06

标签: haskell

如何编写一个takeWhile来保持第一个与条件不匹配的元素?

示例(显然我的例子比这更棘手):

而不是takeWhile (\× - > x! = 3) [1..10]返回[1,2]我需要[1,2,3]

我想到了(takeWhile myFunc myList) ++ [find myFunc myList],但这意味着我需要通过我的清单2次......

有什么想法吗?

3 个答案:

答案 0 :(得分:9)

您可以使用spanbreak

λ> span (/=3) [1..10]
([1,2],[3,4,5,6,7,8,9,10])

所以你可以这样做:

takeWhileInc :: (a -> Bool) -> [a] -> [a]
takeWhileInc p xs = case zs of [] -> error "not found"
                               (z:_) -> ys ++ [z]
  where
    (ys, zs) = span p xs

(或者当zs为空时你想要发生什么,因为没有3 被发现了。)

答案 1 :(得分:7)

你可以自己动手。

takeWhileOneMore :: (a -> Bool) -> [a] -> [a]
takeWhileOneMore p = foldr (\x ys -> if p x then x:ys else [x]) []

将其与

进行比较
takeWhile :: (a -> Bool) -> [a] -> [a]
takeWhile p = foldr (\x ys -> if p x then x:ys else []) []

显式递归对此也没问题。

takeWhileOneMore :: (a -> Bool) -> [a] -> [a]
takeWhileOneMore p [] = []
takeWhileOneMore p (x:xs) = 
   if p x
   then x : takeWhileOneMore p xs
   else [x]

答案 2 :(得分:0)

我更喜欢使用基本功能,比如以智能方式重新使用takeWhile来获得所需的结果。例如,您可以创建一个新的谓词列表,第一个元素为TruetakeWhile此列表为真:

takeWhileP1 p xs = map snd (takeWhile fst (zip (True:map p xs) xs)

这也很好地概括了(在这种形式下不一定有效):

takeWhilePlusN n p xs = map snd (takeWhile fst (zip (replicate n True ++ map p xs) xs))

或者更容易阅读:

takeWhilePlusN n p xs =
  let preds     = replicate n True ++ map p xs
      annotated = zip preds xs
  in map snd (takeWhile fst annotated)

结果:

*Main> takeWhilePlusN 3 (<5) [1..10]
[1,2,3,4,5,6,7]
*Main> takeWhilePlusN 1 (<5) [1..10]
[1,2,3,4,5]
*Main> takeWhileP1 (<5) [1..10]
[1,2,3,4,5]
*Main> takeWhile (<5) [1..10]
[1,2,3,4]