r2rs_base/func/rle.rs
1// "Whatever you do, work at it with all your heart, as working for the Lord,
2// not for human masters, since you know that you will receive an inheritance
3// from the Lord as a reward. It is the Lord Christ you are serving."
4// (Col 3:23-24)
5
6#[derive(Debug, Clone, PartialEq)]
7pub struct RunLengthEncoding<T: Clone + PartialEq> {
8 pub length: usize,
9 pub value: T,
10}
11
12/// Run Length Encoding
13///
14/// ## Description:
15///
16/// Compute the lengths and values of runs of equal values in a vector
17/// - or the reverse operation.
18///
19/// ## Usage:
20///
21/// rle(x)
22/// inverse.rle(x, ...)
23///
24/// #### S3 method for class 'rle'
25/// print(x, digits = getOption("digits"), prefix = "", ...)
26///
27/// ## Arguments:
28///
29/// * x: a vector (atomic, not a list) for ‘rle()’; an object of class
30/// ‘"rle"’ for ‘inverse.rle()’.
31/// * ...: further arguments; ignored here.
32/// * digits: number of significant digits for printing, see ‘print.default’.
33/// * prefix: character string, prepended to each printed line.
34///
35/// ## Details:
36///
37/// ‘vector’ is used in the sense of ‘is.vector’.
38///
39/// Missing values are regarded as unequal to the previous value, even
40/// if that is also missing.
41///
42/// ‘inverse.rle()’ is the inverse function of ‘rle()’, reconstructing
43/// ‘x’ from the runs.
44///
45/// ## Value:
46///
47/// ‘rle()’ returns an object of class ‘"rle"’ which is a list with
48/// components:
49///
50/// lengths: an integer vector containing the length of each run.
51///
52/// values: a vector of the same length as ‘lengths’ with the corresponding values.
53/// ‘inverse.rle()’ returns an atomic vector.
54///
55/// ## Examples:
56///
57/// ```r
58/// x <- rev(rep(6:10, 1:5))
59/// rle(x)
60/// ## lengths [1:5] 5 4 3 2 1
61/// ## values [1:5] 10 9 8 7 6
62///
63/// z <- c(TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, TRUE, TRUE, TRUE)
64/// rle(z)
65/// rle(as.character(z))
66/// print(rle(z), prefix = "..| ")
67/// ```
68pub fn rle<T: Clone + PartialEq>(x: &[T]) -> Vec<RunLengthEncoding<T>> {
69 x.iter().fold(Vec::new(), |mut v, x| {
70 if v.is_empty() {
71 v.push(RunLengthEncoding {
72 length: 1,
73 value: x.clone(),
74 });
75 v
76 } else {
77 let len = v.len();
78 let last = &mut v[len - 1];
79 if last.value == x.clone() {
80 last.length += 1;
81 } else {
82 v.push(RunLengthEncoding {
83 length: 1,
84 value: x.clone(),
85 });
86 }
87 v
88 }
89 })
90}
91
92/// Run Length Encoding
93///
94/// ## Description:
95///
96/// Compute the lengths and values of runs of equal values in a vector
97/// - or the reverse operation.
98///
99/// ## Usage:
100///
101/// rle(x)
102/// inverse.rle(x, ...)
103///
104/// ## S3 method for class 'rle'
105/// print(x, digits = getOption("digits"), prefix = "", ...)
106///
107/// ## Arguments:
108///
109/// * x: a vector (atomic, not a list) for ‘rle()’; an object of class
110/// ‘"rle"’ for ‘inverse.rle()’.
111/// * ...: further arguments; ignored here.
112/// * digits: number of significant digits for printing, see
113/// print.default’.
114/// * prefix: character string, prepended to each printed line.
115///
116/// ## Details:
117///
118/// ‘vector’ is used in the sense of ‘is.vector’.
119///
120/// Missing values are regarded as unequal to the previous value, even
121/// if that is also missing.
122///
123/// ‘inverse.rle()’ is the inverse function of ‘rle()’, reconstructing
124/// ‘x’ from the runs.
125///
126/// ## Value:
127///
128/// ‘rle()’ returns an object of class ‘"rle"’ which is a list with
129/// components:
130///
131/// lengths: an integer vector containing the length of each run.
132///
133/// values: a vector of the same length as ‘lengths’ with the
134/// corresponding values.
135///
136/// ‘inverse.rle()’ returns an atomic vector.
137///
138/// ## Examples:
139///
140/// ```r
141/// x <- rev(rep(6:10, 1:5))
142/// rle(x)
143/// ## lengths [1:5] 5 4 3 2 1
144/// ## values [1:5] 10 9 8 7 6
145///
146/// z <- c(TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, TRUE, TRUE, TRUE)
147/// rle(z)
148/// rle(as.character(z))
149/// print(rle(z), prefix = "..| ")
150///
151/// N <- integer(0)
152/// stopifnot(x == inverse.rle(rle(x)),
153/// identical(N, inverse.rle(rle(N))),
154/// z == inverse.rle(rle(z)))
155/// ```
156pub fn inverse_rle<T: Clone + PartialEq>(x: &[RunLengthEncoding<T>]) -> Vec<T> {
157 x.iter()
158 .flat_map(|RunLengthEncoding { length, value }| vec![value.clone(); *length])
159 .collect()
160}