RosettaCodeData/Task/Run-length-encoding/Rust/run-length-encoding.rs

56 lines
1.7 KiB
Rust

fn encode(s: &str) -> String {
s.chars()
// wrap all values in Option::Some
.map(Some)
// add an Option::None onto the iterator to clean the pipeline at the end
.chain(std::iter::once(None))
.scan((0usize, '\0'), |(n, c), elem| match elem {
Some(elem) if *n == 0 || *c == elem => {
// the run continues or starts here
*n += 1;
*c = elem;
// this will not have an effect on the final string because it is empty
Some(String::new())
}
Some(elem) => {
// the run ends here
let run = format!("{}{}", n, c);
*n = 1;
*c = elem;
Some(run)
}
None => {
// the string ends here
Some(format!("{}{}", n, c))
}
})
// concatenate together all subresults
.collect()
}
fn decode(s: &str) -> String {
s.chars()
.fold((0usize, String::new()), |(n, text), c| {
if c.is_ascii_digit() {
// some simple number parsing
(
n * 10 + c.to_digit(10).expect("invalid encoding") as usize,
text,
)
} else {
// this must be the character that is repeated
(0, text + &format!("{}", c.to_string().repeat(n)))
}
})
.1
}
fn main() {
let text = "WWWWWWWWWWWWBWWWWWWWWWWWWBBBWWWWWWWWWWWWWWWWWWWWWWWWBWWWWWWWWWWWWWW";
let encoded = encode(text);
let decoded = decode(&encoded);
println!("original: {}\n encoded: {}\n decoded: {}", text, encoded, decoded);
assert_eq!(text, decoded);
}