format!("Hello"); // => "Hello"
format!("Hello, {}!", "world"); // => "Hello, world!"
format!("The number is {}", 1); // => "The number is 1"
format!("{:?}", (3, 4)); // => "(3, 4)"
format!("{value}", value=4); // => "4"
format!("{} {}", 1, 2); // => "1 2"
format!("{:04}", 42); // => "0042" with leading zeros
printf
style than directly putting it inline in the strings.
let value = 4; format!("{value}");
in rust as far as I know
for index in 3..0 { }
for index in (0..3).rev() { }
You can use itertools crate https://docs.rs/itertools/0.6.0/itertools/trait.Itertools.html#method.join
let result: Vec<String> = (verse_to..(verse_from+1))
.rev()
.map(|i| (&verse(i)).clone())
.collect::<Vec<String>>();
result.as_slice().join("\n")
this code looks horrible, any advice?
var result = String.Join("\n", Enumerable.Range(verseFrom, verseTo).Reverse().Select(i => verse(i));
verse
return?
.map(|i| (&verse(i)).clone())
and should be able to use .map(verse)
let result = (verse_to..verse_from+1).rev().map(verse).collect::<Vec<_>>().join("\n")
.Select(i => verse(i))
to :P You can write just .Select(verse)
.collect::<Vec<_>>()
necessary? I mean why isn't it possible to join on an iterator?
join
method. It's just not in the standard library (yet).
join
for Iterator<Item=U>, U: Copy
can be implemented relatively easily https://play.rust-lang.org/?gist=8339f4b984ba66df8c84c973eb282ed8&version=stable&backtrace=0itertools
has join https://docs.rs/itertools/0.6.0/itertools/fn.join.html which might be one reason why I can't find an RFC or PR for this to be in std
(1..range_end).sum()
?
let s: i32 = (1..20).sum();
std::iter::Sum<u8>
is not implemented for u32
u32
s into one u8
?
.map(|v|v as u32).sum()
or .map(|&v|v as u32).sum()
impl Sum<uX> for uY
where X < Y
.iter()
on any collection will create you a value that keeps track of the position inside the vec for example; if this was a feature of the collection itself you couldn't have multiple iterators created to the same collection at the same time
mut
allows borrows, mutable borrow and mutation. they are more orthogonal than on the same axis
into_iter()
method, consuming it. So that means items inside of Vec are no longer owned by the Vec and can/will be moved out (otherwise they will be dropped).
pub fn encode(input: &str) -> String {
let runs = input
.chars()
.fold(Vec::<(char, u8)>::new(), |mut acc, c| {
if let Some(last) = acc.iter().cloned().last() {
if last.0 == c {
acc.pop();
acc.push((last.0, last.1 + 1));
} else {
acc.push((c, 1));
}
} else {
acc.push((c, 1));
}
acc
});
runs.iter()
.map(|x| if x.1 > 1 {
format!("{}{}", x.1, x.0)
} else {
format!("{}", x.0)
})
.collect::<Vec<_>>()
.join("")
}
I'm trying to do simple RLE-compression using map and fold... Any advice on how to avoid pop/push? or avoid cloning of acc
acc.iter().cloned().last()
- don't do that, it'll kill your performance!
acc
into two parts - one where you get (and copy) the character to test against, and one to actually edit acc
.
pub fn encode(input: &str) -> String {
let mut chars = input.chars();
match chars.next() {
None => "".to_string(),
Some(first_char) => {
let initial_state = vec!((first_char, 1));
let runs = chars.fold(initial_state, |mut acc, c| { // acc is never empty
let &(last_char, _) = acc.last().unwrap();
if last_char == c {
(*acc.last_mut().unwrap()).1 += 1
} else {
acc.push((c, 1))
}
acc
});
runs.iter() // from here on the same as yours
initial_state
thing isn't strictly necessary but it's a lot cleaner and could potentially be more efficient (but I suspect all those if acc.len() == 0
checks would get optimised out anyway).
acc
anyway the fold is redundant and can be replaced with a loop:pub fn encode(input: &str) -> String {
let mut chars = input.chars();
match chars.next() {
None => "".to_string(),
Some(first_char) => {
let mut acc = vec!((first_char, 1)); // acc is never empty
for c in chars {
let &(last_char, _) = acc.last().unwrap();
if last_char == c {
(*acc.last_mut().unwrap()).1 += 1;
} else {
acc.push((c, 1));
}
};
acc.iter()
.map(|x| if x.1 > 1 {
format!("{}{}", x.1, x.0)
} else {
format!("{}", x.0)
})
.collect::<Vec<_>>()
.join("")
}
}
}
group
function that splits chars
into blocks of the same char.
extern crate itertools;
use itertools::Itertools;
fn main() {
let groups = "aabccccccdaasd".chars().group_by(|&c|c);
let res: String = groups.into_iter().map(|(c, i)| {
let len = i.count();
if len == 1 {
format!("{}", c)
} else {
format!("{}{}", len, c)
}
}).collect();
println!("{:?}", res);
}
i.count()
traverse group of chars second time.
itertools::structs::Group
, essentially it's iterator
i
is your group of chars, i.e. aaa
, bb
or the like. So unfortunately you do need to count them.
Vec<String>
and keep the "last" element in a mut (char, u8)
directly instead of storing the intermediate Vec<(char, u8)>
and then converting to the Vec<String>
in a second pass.
i.count()
traverses them the second time and not the first?
acc
be mutable and you append to it, you create it by chaining closures. (I think).
group_by
) or a manual and mutable solution that will probably be faster.
fn encode(input: &str) -> Vec<(char, u8)>
group_by
IMO.