8
votes

I have a 'compressed' stream of value to which is attached the number of occurence of that value, for instance :

let a = [ (),1; (),4; (),3;]

I would like to 'uncompress' that sequence and emit the original sequence. I could define a repeat combinator to yield! to that effect

let rec repeat avalue n =  seq { if n > 0 then 
                                    yield avalue; yield! repeat avalue (n-1) }

let b = seq { for v,n in a do
                yield! repeat v n }  |> Seq.toList

Is there a way to express that inline, in the form of a composition ?

let c = a |> Seq.XXX(fun e -> ...) 
3

3 Answers

7
votes

You can do this using Enumerable.Repeat:

> Seq.collect Enumerable.Repeat [ 1, 2; 3, 4; 5, 6 ] |> List.ofSeq;;
val it : int list = [1; 1; 3; 3; 3; 3; 5; 5; 5; 5; 5; 5]
3
votes
let rec repeat (item,n) = seq { if n > 0 then yield item; yield! repeat(item, n-1)}
a |> Seq.collect repeat

For example,

[('a',2); ('b',2)] |> Seq.collect repeat

val it: seq<char> = seq ['a';'a';'b';'b']
3
votes

How about

let c = a |> Seq.collect (fun (v,i) -> [1..i] |> Seq.map (fun x -> v))

I don't know a library function similar to Enumerable.Repeat; if someone knows of one, please add a comment.

EDIT

I have found a library function similar to Enumerable.Repeat, though it is in the List module:

let c = a |> Seq.collect (fun (v,i) -> List.replicate i v)

This would be more elegant if the pairs in the source sequence were reversed:

let c = a |> Seq.collect ((<||) List.replicate)

So it seems that Enumerable.Repeat (as in the accepted answer) does indeed make the best solution, since its tupled argument matches the sequence elements:

let c = a |> Seq.collect Enumerable.Repeat

If anyone knows of a similarly elegant solution that stays within the F# library, please add a comment; thanks.