-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathRunLengthEncoding.fs
executable file
·68 lines (53 loc) · 2.08 KB
/
RunLengthEncoding.fs
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
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
module RunLengthEncoding
open System
open FsCheck
open FsCheck.Xunit
// http://booksites.artima.com/scalacheck/examples/html/ch04.html#sec6
////////////////////////////////////////////////////////////////////////////////
// Implementation code
////////////////////////////////////////////////////////////////////////////////
// e.g.
// ['a'; 'a'; 'a'; 'b'; 'a'; 'a'; 'x'; 'x'; 'x']
// [(3, 'a'); (1, 'b'); (2, 'a'); (3, 'x')]
let rec runLengthEnc (xs: 'a list): (int * 'a) list =
match xs with
| hd :: _ ->
// let (hds, remainder) = List.partition (fun x -> x = hd) xs
let hds = List.takeWhile (fun x -> x = hd) xs
let n = List.length hds
let (_, remainder) = List.splitAt n xs
(n, hd) :: runLengthEnc remainder
| _ ->
[]
let runLengthDec (r: (int * 'a) list): 'a list =
List.collect (fun t -> List.replicate (fst t) (snd t)) r
////////////////////////////////////////////////////////////////////////////////
// Custom generators
////////////////////////////////////////////////////////////////////////////////
let alphaNumChar: char Gen =
Gen.elements <| ['a'..'z'] @ ['A'..'Z'] @ ['0'..'9']
let rleItem: (int * char) Gen =
gen {
let! n = Gen.choose (1, 20)
let! c = alphaNumChar
return n, c
}
let rec rleList(size: int): (int * char) list Gen =
if (size <= 1) then Gen.map List.singleton rleItem
else gen {
let! tail = rleList (size - 1)
let (_, c1) = List.head tail
let! head = Gen.where (fun t -> snd t <> c1) rleItem
return head :: tail
}
let genOutput: (int * char) list Gen = Gen.sized rleList
type CustomArbitraries =
static member RleList() = Arb.fromGen genOutput
////////////////////////////////////////////////////////////////////////////////
// Property test
////////////////////////////////////////////////////////////////////////////////
[<Properties(Arbitrary=[| typeof<CustomArbitraries> |])>]
module RunLengthEncodingWithProperties =
[<Property>]
let ``run length encoding round trip`` (r: (int * char) list) =
runLengthEnc(runLengthDec(r)) = r