3 people like it.

Splitting a sequence based on separator condition

Whilst working on a google API wrapper, I came across the need to separate a sequence into sub-sequences based on a separator condition. This also led to a requirement for versions of takeWhile and skipWhile which also include the element which first breaks the condition predicate.

 1: 
 2: 
 3: 
 4: 
 5: 
 6: 
 7: 
 8: 
 9: 
10: 
11: 
12: 
13: 
14: 
15: 
16: 
17: 
18: 
19: 
20: 
21: 
let notEmpty s = not (Seq.isEmpty s)

// inclusive version of takeWhile - includes the element which broke the condition
let takeWhileInc cond s =
  seq {
    yield! s |> Seq.takeWhile cond
    let r = s |> Seq.skipWhile cond
    if notEmpty r then yield r |> Seq.head
  }
// inclusive version of skipWhile - also skips the first element which broke the condition  
let skipWhileInc cond s =
  let r = s |> Seq.skipWhile cond
  if notEmpty r then (r |> Seq.skip 1) else r

// split a large sequence into a sequence of sequences, determined by a splitter condition
let rec splitSubSequences cond s =
  seq {
    if not (s |> Seq.isEmpty) then
      yield (s |> takeWhileInc cond)
      yield! (s |> skipWhileInc cond |> splitSubSequences cond)
    }
val notEmpty : s:seq<'a> -> bool

Full name: Script.notEmpty
val s : seq<'a>
val not : value:bool -> bool

Full name: Microsoft.FSharp.Core.Operators.not
module Seq

from Microsoft.FSharp.Collections
val isEmpty : source:seq<'T> -> bool

Full name: Microsoft.FSharp.Collections.Seq.isEmpty
val takeWhileInc : cond:('a -> bool) -> s:seq<'a> -> seq<'a>

Full name: Script.takeWhileInc
val cond : ('a -> bool)
Multiple items
val seq : sequence:seq<'T> -> seq<'T>

Full name: Microsoft.FSharp.Core.Operators.seq

--------------------
type seq<'T> = System.Collections.Generic.IEnumerable<'T>

Full name: Microsoft.FSharp.Collections.seq<_>
val takeWhile : predicate:('T -> bool) -> source:seq<'T> -> seq<'T>

Full name: Microsoft.FSharp.Collections.Seq.takeWhile
val r : seq<'a>
val skipWhile : predicate:('T -> bool) -> source:seq<'T> -> seq<'T>

Full name: Microsoft.FSharp.Collections.Seq.skipWhile
val head : source:seq<'T> -> 'T

Full name: Microsoft.FSharp.Collections.Seq.head
val skipWhileInc : cond:('a -> bool) -> s:seq<'a> -> seq<'a>

Full name: Script.skipWhileInc
val skip : count:int -> source:seq<'T> -> seq<'T>

Full name: Microsoft.FSharp.Collections.Seq.skip
val splitSubSequences : cond:('a -> bool) -> s:seq<'a> -> seq<seq<'a>>

Full name: Script.splitSubSequences
Raw view Test code New version

More information

Link:http://fssnip.net/n8
Posted:10 years ago
Author:Chris Ballard
Tags: sequence , separator , subsequence