❮❮❮
Karamellpudding
❮❮❮
❯❯❯
Identity wrappers in ML
❯❯❯
Interspersing elements into a sequence
Various approaches
Reading time: 2 min.
Problem
Implement
/// Inserts after period elements the filler element into original sequence.
let intersperse (period : int) (filler : 'a) (original : seq<'a>) : seq<'a> =
failwith "nyi
The call should work as
seq { for i in 1..5 -> i} = seq { 1; 2; 3; 4}
intersperse 0 seq { for i in 1..5 -> i} = seq { 1; 0; 2; 0; 3; 0; 4 }
With standard lib
let intersperse (period : int) (filler : 'a) (original : seq<'a>) : seq<'a> =
if period <= 0
then failwith $"Period must be > 0 but is %i{period}."
original
|> Seq.chunkBySize period
|> Seq.mapi (fun i b ->
seq {
if i > 0 then yield filler
yield! b
}
)
|> Seq.concat
With local state for first block
let intersperse (period : int) (filler : 'a) (original : seq<'a>) : seq<'a> =
if period <= 0
then failwith $"Period must be > 0 but is %i{period}."
let notFirstBlock = ref false
original
|> Seq.chunkBySize period
|> Seq.map (fun b ->
seq {
if notFirstBlock
then notFirstBlock.Value <- true
else yield filler
yield! b
}
)
|> Seq.concat
With IEnumerator and without intermediate arrays
let intersperse (period : int) (filler : 'a) (original : seq<'a>) : seq<'a> =
if period <= 0
then failwith $"Period must be > 0 but is %i{period}."
let enum = original.GetEnumerator ()
let inblock = ref 0
seq {
if enum.MoveNext ()
then
while enum.MoveNext () && inblock.Value < period do
yield enum.Current
inblock.Value <- inblock.Value + 1
inblock.Value <- 0
while enum.MoveNext () do
yield filler
while enum.MoveNext () && inblock.Value < period do
yield enum.Current
inblock.Value <- inblock.Value + 1
inblock.Value <- 0
}