69 people like it.

Partition a sequence until a predicate is satiated

This function is given a partition predicate and a sequence. Until the predicate returns false, a list will be filled with elements. When it is, both the list and the remainder of the sequence will be returned. Note that this example preserves the laziness of the unchecked sequence elements.

 1: 
 2: 
 3: 
 4: 
 5: 
 6: 
 7: 
 8: 
 9: 
10: 
11: 
12: 
13: 
14: 
15: 
16: 
17: 
18: 
19: 
20: 
21: 
22: 
23: 
24: 
25: 
26: 
27: 
28: 
29: 
30: 
module Seq =
    let paritionWhile (pred : _ -> bool) (sequence : _ seq) : _ list * _ seq = 
        let en = sequence.GetEnumerator ()
        let wasGood = ref true
        let sublist = 
            [
                while !wasGood && en.MoveNext() do
                    if pred en.Current then yield en.Current
                    else wasGood := false
            ]
        let remainder = 
            seq { 
                    if not !wasGood then yield en.Current
                    while en.MoveNext() do yield en.Current 
                }
        sublist, remainder

[<Fact>]
let subsetUntil_ShouldReturnProperSubset () =
    let testSeq = seq { for i in 1 .. 6 do yield i }
    let sub, remainder = testSeq |> Seq.partitionWhile (fun x -> x <= 3)
    Assert.Equal( [1; 2; 3], sub )
    Assert.Equal( [4; 5; 6], remainder |> Seq.toList )

[<Fact>] 
let subsetUntil_shouldReturnEmptyListandSeqWhenEmptyGiven () =
    let testSeq = Seq.empty
    let sub, remainder = testSeq |> Seq.partitionWhile (fun x -> x <= 3)
    Assert.Empty sub
    Assert.Empty remainder
module Seq

from Microsoft.FSharp.Collections
val paritionWhile : pred:('a -> bool) -> sequence:seq<'a> -> 'a list * seq<'a>

Full name: Script.Seq.paritionWhile
val pred : ('a -> bool)
type bool = System.Boolean

Full name: Microsoft.FSharp.Core.bool
val sequence : seq<'a>
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<_>
type 'T list = List<'T>

Full name: Microsoft.FSharp.Collections.list<_>
val en : System.Collections.Generic.IEnumerator<'a>
System.Collections.Generic.IEnumerable.GetEnumerator() : System.Collections.Generic.IEnumerator<'a>
val wasGood : bool ref
Multiple items
val ref : value:'T -> 'T ref

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

--------------------
type 'T ref = Ref<'T>

Full name: Microsoft.FSharp.Core.ref<_>
val sublist : 'a list
System.Collections.IEnumerator.MoveNext() : bool
property System.Collections.Generic.IEnumerator.Current: 'a
val remainder : seq<'a>
val not : value:bool -> bool

Full name: Microsoft.FSharp.Core.Operators.not
val subsetUntil_ShouldReturnProperSubset : unit -> 'a

Full name: Script.subsetUntil_ShouldReturnProperSubset
val testSeq : seq<int>
val i : int
val sub : obj
val remainder : obj
Multiple items
module Seq

from Script

--------------------
module Seq

from Microsoft.FSharp.Collections
val toList : source:seq<'T> -> 'T list

Full name: Microsoft.FSharp.Collections.Seq.toList
val subsetUntil_shouldReturnEmptyListandSeqWhenEmptyGiven : unit -> 'a

Full name: Script.subsetUntil_shouldReturnEmptyListandSeqWhenEmptyGiven
val testSeq : seq<'b>
val empty<'T> : seq<'T>

Full name: Microsoft.FSharp.Collections.Seq.empty

More information

Link:http://fssnip.net/1I
Posted:13 years ago
Author:Rick Minerich
Tags: seq , list , subset , partition