简体   繁体   English

Haskell takeWhile + 1

[英]Haskell takeWhile + 1

How can I write a takeWhile that would keep the first element that doesn't match the condition?我如何编写一个 takeWhile 来保留第一个不匹配条件的元素?

Example (obviously my example is trickier than this) :示例(显然我的示例比这更棘手):

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

I thought of (takeWhile myFunc myList) ++ [find myFunc myList] but it means I need to go through my list 2 times...我想到了(takeWhile myFunc myList) ++ [find myFunc myList]但这意味着我需要遍历我的列表 2 次...

Any idea?任何的想法?

You can use span or break . 你可以使用spanbreak

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

So you can do something like this: 所以你可以这样做:

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

(Or whatever you want to happen when zs is empty because no 3 was found.) (或任何你希望发生的事情时, zs ,因为没有空3被发现。)

You can roll your own. 你可以自己动手。

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

Compare it with 比较它

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

Explicit recursion would also be fine for this. 显式递归对此也没问题。

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

I like to use the base function more than many people do, such as re-using takeWhile in an intelligent way to get the desired result. 我比许多人更喜欢使用基本功能,例如以智能方式重新使用takeWhile来获得所需的结果。 For example, you can create a new list of predicates with the first element being True and takeWhile this list is true: 例如,您可以创建一个新的谓词列表,其中第一个元素为True并且takeWhile此列表为true:

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

This generalizes nicely as well (not necessarily efficient in this form): 这也很好地概括(在这种形式下不一定有效):

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

Or perhaps easier to read: 或者更容易阅读:

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

And the result: 结果如下:

*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]

When the condition fails for a element, instead of terminating with empty list, we can return the element.当某个元素的条件失败时,我们可以返回该元素,而不是以空列表终止。

takeWhileInclusive :: (a->Bool)  -> [a] -> [a]
takeWhileInclusive _ [] = []
takeWhileInclusive predicate (x:xs) = if predicate x 
                                         then do (x: takeWhileInclusive predicate xs)
                                            else [x]

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM