rwallace
rwallace

Reputation: 33385

Combination takeWhile, skipWhile

In F#, I find when I want to use takeWhile, I usually also want to use skipWhile, that is, take the list prefix that satisfies a predicate, and also remember the rest of the list for subsequent processing. I don't think there is a standard library function that does both, but I can write one easily enough.

My question is, what should this combination be called? It's obvious enough that there should be a standard name for it; what is it? Best I've thought of so far is split, which seems consistent with splitAt.

Upvotes: 5

Views: 741

Answers (3)

TheQuickBrownFox
TheQuickBrownFox

Reputation: 10624

This part of your question stood out to me (emphasis mine):

take the list prefix that satisfies a predicate, and also remember the rest of the list for subsequent processing

I am guessing that you want to recurse with the rest of the list and then apply this splitting function again. This is what I have wanted to do a few times before. Initially, I wrote the function that I think you are describing but after giving it more thought I realised that there might be a more general way to think about it and avoid the recursion completely, which usually makes code simpler. This is the function I came up with.

module List =
    let groupAdjacentBy f xs =
        let mutable prevKey, i = None, 0
        xs
        |> List.groupBy (fun x ->
            let key = f x
            if prevKey <> Some key then
                i <- i + 1
                prevKey <- Some key
            (i, key))
        |> List.map (fun ((_, k), v) -> (k, v))

let even x = x % 2 = 0
List.groupAdjacentBy even [1; 3; 2; 5; 4; 6]
// [(false, [1; 3]); (true, [2]); (false, [5]); (true, [4; 6])]

I found this one easier to name and more useful. Maybe it works for your current problem. If you don't need the group keys then you can get rid of them by adding |> List.map snd.

As much as I usually avoid mutation, using it here allowed me to use List.groupBy and avoid writing more code.

Upvotes: 1

bergey
bergey

Reputation: 3071

span is another name I've seen for this function. For example, in Haskell

Upvotes: 3

Bryan Watts
Bryan Watts

Reputation: 45445

.slice could capture the intent of a contiguous range:

List.slice skipPredicate takePredicate

Upvotes: 0

Related Questions