how to do Seq.takeWhile + one item in F#

let duplicateHead xs = seq { yield Seq.head xs; yield! xs }
let filter predicate xs =
    xs
    |> duplicateHead
    |> Seq.pairwise
    |> Seq.takeWhile (fst >> predicate)
    |> Seq.map snd

Alternative version of duplicateHead, in case if you don't like computation expression here:

let duplicateHead' xs =
    Seq.append 
        (Seq.head xs)
        xs

This approach is based on building tuples of current and next element. The predicate is being applied to the current element, but the following one is returned.

NOTE: It is not safe for cases when predicate fails on the very first element. In order to make it working fine, you have to re-work duplicateHead by adding an element that would certainly pass the predicate.


Don't really get what is the problem with your solution.

Two small corrections:

(1) Use sequence expression for readability.

(2) Use Seq.truncate instead of Seq.take in case the input sequence is empty.

let myFilter predicate s = 
    seq { yield! Seq.takeWhile predicate s
          yield! s |> Seq.skipWhile predicate |> Seq.truncate 1 }

Another late answer but it is "functional", simple and does not read any elements past the last one in the result sequence.

let myFilter predicate =
    Seq.collect (fun x -> [Choice1Of2 x; Choice2Of2 (predicate x)])
    >> Seq.takeWhile (function | Choice1Of2 _ -> true | Choice2Of2 p -> p)
    >> Seq.choose (function | Choice1Of2 x -> Some x | Choice2Of2 _ -> None)

The lack of support for break in computation expressions is a bit annoying. It does not fit well with the model used by F# (which is why it is not supported), but it would be really useful in this case.

If you want to implement this using just a single iteration over the sequence, then I think the cleanest solution is to just use the underlying structure of sequences and write it as a recursive loop using IEnumerator<'T>

This is fairly short (compared to other solutions here) and it is quite clear code too:

let myFilter predicate (s:seq<_>) = 
  /// Iterates over the enumerator, yielding elements and
  /// stops after an element for which the predicate does not hold
  let rec loop (en:IEnumerator<_>) = seq {
    if en.MoveNext() then
      // Always yield the current, stop if predicate does not hold
      yield en.Current
      if predicate en.Current then
        yield! loop en }

  // Get enumerator of the sequence and yield all results
  // (making sure that the enumerator gets disposed)
  seq { use en = s.GetEnumerator()
        yield! loop en }