2 people like it.

# Gluing-up sequence members

While thinking on Project Euler Problem 40 solution (http://projecteuler.net/index.php?section=problems&id=40) the following subproblem has surfaced: how to glue up string presentations of a sequence members to reach a given length of result string. The snippet gives at least 3 different implementations of such function with performance comparison; as a bonus a solution to Problem 40 is given.

 ``` 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: 31: 32: 33: 34: 35: 36: 37: ``` ``````open System open System.Text (Performance measurement instrumentation) // Glue up using Seq.collect (worst peformer) let glueUp1 len ss = new string ( ss |> Seq.collect (fun s -> Seq.ofArray <| s.ToString().ToCharArray()) |> Seq.take len |> Seq.toArray) // Glue up using Seq.scan + Seq.skipWhile let glueUp2 len ss = ss |> Seq.scan (fun (accum: StringBuilder) s -> accum.Append(s.ToString())) (StringBuilder()) |> Seq.skipWhile (fun x -> x.Length < len) |> Seq.head |> string |> fun x -> x.Substring(0, len) // Glue up using Seq.pick and a closure over StringBuilder (best performer) let glueUp3 len ss = let glue len = let accum = StringBuilder() fun item -> if accum.Length >= len then Some(accum.ToString()) else accum.Append(item.ToString()) |> ignore None ss |> Seq.pick(glue len) |> fun x -> x.Substring(0, len) (Performance measurement) (Project Euler Problem 40 Solution) ``````
namespace System
namespace System.Text
let time f x =
let t = new System.Diagnostics.Stopwatch()
t.Start()
try
f x
finally
printf "Took %dms\n" t.ElapsedMilliseconds
val glueUp1 : len:int -> ss:seq<'a> -> string

Full name: Script.glueUp1
val len : int
val ss : seq<'a>
Multiple items
val string : value:'T -> string

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

--------------------
type string = String

Full name: Microsoft.FSharp.Core.string
module Seq

from Microsoft.FSharp.Collections
val collect : mapping:('T -> #seq<'U>) -> source:seq<'T> -> seq<'U>

Full name: Microsoft.FSharp.Collections.Seq.collect
val s : 'a
val ofArray : source:'T [] -> seq<'T>

Full name: Microsoft.FSharp.Collections.Seq.ofArray
Object.ToString() : string
val take : count:int -> source:seq<'T> -> seq<'T>

Full name: Microsoft.FSharp.Collections.Seq.take
val toArray : source:seq<'T> -> 'T []

Full name: Microsoft.FSharp.Collections.Seq.toArray
val glueUp2 : len:int -> ss:seq<'a> -> string

Full name: Script.glueUp2
val scan : folder:('State -> 'T -> 'State) -> state:'State -> source:seq<'T> -> seq<'State>

Full name: Microsoft.FSharp.Collections.Seq.scan
val accum : StringBuilder
Multiple items
type StringBuilder =
new : unit -> StringBuilder + 5 overloads
member Append : value:string -> StringBuilder + 18 overloads
member AppendFormat : format:string * arg0:obj -> StringBuilder + 4 overloads
member AppendLine : unit -> StringBuilder + 1 overload
member Capacity : int with get, set
member Chars : int -> char with get, set
member Clear : unit -> StringBuilder
member CopyTo : sourceIndex:int * destination:char[] * destinationIndex:int * count:int -> unit
member EnsureCapacity : capacity:int -> int
member Equals : sb:StringBuilder -> bool
...

Full name: System.Text.StringBuilder

--------------------
StringBuilder() : unit
StringBuilder(capacity: int) : unit
StringBuilder(value: string) : unit
StringBuilder(value: string, capacity: int) : unit
StringBuilder(capacity: int, maxCapacity: int) : unit
StringBuilder(value: string, startIndex: int, length: int, capacity: int) : unit
StringBuilder.Append(value: char []) : StringBuilder
StringBuilder.Append(value: obj) : StringBuilder
StringBuilder.Append(value: uint64) : StringBuilder
StringBuilder.Append(value: uint32) : StringBuilder
StringBuilder.Append(value: uint16) : StringBuilder
StringBuilder.Append(value: decimal) : StringBuilder
StringBuilder.Append(value: float) : StringBuilder
StringBuilder.Append(value: float32) : StringBuilder
StringBuilder.Append(value: int64) : StringBuilder
StringBuilder.Append(value: int) : StringBuilder
val skipWhile : predicate:('T -> bool) -> source:seq<'T> -> seq<'T>

Full name: Microsoft.FSharp.Collections.Seq.skipWhile
val x : StringBuilder
property StringBuilder.Length: int
val head : source:seq<'T> -> 'T

val x : string
String.Substring(startIndex: int) : string
String.Substring(startIndex: int, length: int) : string
val glueUp3 : len:int -> ss:seq<'a> -> string

Full name: Script.glueUp3
val glue : (int -> 'b -> string option)
val item : 'b
union case Option.Some: Value: 'T -> Option<'T>
StringBuilder.ToString() : string
StringBuilder.ToString(startIndex: int, length: int) : string
val ignore : value:'T -> unit

Full name: Microsoft.FSharp.Core.Operators.ignore
union case Option.None: Option<'T>
val pick : chooser:('T -> 'U option) -> source:seq<'T> -> 'U

Full name: Microsoft.FSharp.Collections.Seq.pick
time (glueUp1 1000000) (Seq.initInfinite(fun x -> x)) |> ignore
time (glueUp2 1000000) (Seq.initInfinite(fun x -> x)) |> ignore
time (glueUp3 1000000) (Seq.initInfinite(fun x -> x)) |> ignore
// Project Euler Problem 40
let digits = Seq.initInfinite (fun n -> n) |> glueUp2 1000001
[1;10;100;1000;10000;100000;1000000]
|> List.fold (fun result x -> result * Int32.Parse(string digits.[x])) 1
|> printfn "Project Euler Problem 40 Answer: %d"