:timing
:sccache 1
Tips & Traps¶
Module std::collections has a good summary on when to each which collection in Rust.
Be aware of possible performance penalty when you write functional programming style code especially when you have large collections.
Functional programming methods (
map
,filter
, etc.) can only apply to Itrators and Ranges instead of concrete collections types.itertools is a crate providing additional iterator related functionalities.
Iterating a generic iterator (
dyn Iterator<Item = T>
) is slower than iterating a slice&[T]
even though the generic iterator is backed by a slice.itertools::Itertools::combinations build an internal buffer first and then generate an iterator of combinations based on it. It can be faster to develop an iteration algorithm based a slice directly instead of an iterator. If performance is critical, it helps to pre-generate combinations and cache them.
filter¶
v1.iter().filter(|&&x| x > 0).count()
v1.iter().max().unwrap()
*v1.iter().max().unwrap()
v1.iter().filter(|x| x > 0).count()
map¶
fold and reduce¶
Iterator.fold is preferred to Iterator.reduce if you do not want to return an Option
.
scan¶
sum and product¶
take, take_while, skip, skip_while¶
let v = vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
v
v.iter().take(3)
v.iter().take(3).collect::<Vec<_>>()
v.iter().take_while(|&&x| x < 3)
v.iter().take_while(|&&x| x < 3).collect::<Vec<_>>()
v.iter().skip(6)
v.iter().skip(6).collect::<Vec<_>>()
v.iter().skip_while(|&&x| x < 6)
v.iter().skip_while(|&&x| x < 6).collect::<Vec<_>>()
zip vs izip vs multizip¶
itertools::zip
is equivalent to Iterator::zip
in the standard library.
itertools::multizip
a generalization of itertools::zip
and Iterator::zip
to zip multip iterators.
itertools::izip
is a macro version of itertools::multizip
and itertools::izip
is preferred for its performance.
Join An Iterator of Strings¶
Empty Separator¶
let words = vec!["alpha", "beta", "gamma"];
let merged: String = words.into_iter().collect();
println!("{}", merged);
Notice that the above code won't work if an array were used.
let words = ["alpha", "beta", "gamma"];
let merged: String = words.into_iter().collect();
println!("{}", merged);
You have to dereference elements using the method .copied()
to fix the issue.
let words = ["alpha", "beta", "gamma"];
let merged: String = words.into_iter().copied().collect();
println!("{}", merged);
:dep itertools = "0.10.0"
use itertools::Itertools;
intersperse¶
We had an example of concatenating an iterable of strings using the method std::iterator::collect
.
However,
std::iterator::collect
(into string)
concatenate strings without seprators.
itertools::itersperse
lets you concatenate an iterable of string with a separator.
let words = ["alpha", "beta", "gamma"];
let merged: String = words.into_iter().intersperse(", ").collect();
println!("{}", merged);
let words = ["alpha", "beta", "gamma"];
let merged: String = words.iter().copied().intersperse(", ").collect();
println!("{}", merged);
let data = vec![1, 1, 2, -2, 6, 0, 3, 1];
for chunk in &data.into_iter().chunks(3) {
assert_eq!(4, chunk.sum());
}
fn find_min<I>(vals: I) -> Option<&'static str> where I: Iterator<Item = &'static str>{
vals.min_by_key(|v| v.len())
}
let s = ["how", "are", "you"];
find_min(s.iter())
fn foo<'a, I>(x: I) -> Option<I::Item> where I: IntoIterator<Item = &'a &'static str> {
x.into_iter().min_by_key(|v| v.len())
}
let s = ["how", "are", "you"];
foo(&s)
fn foo<'a, I: IntoIterator<Item=&'a i32>>(x: I) {
}
let v = vec![1, 2, 3];
foo(&v);
fn foo<'a, I>(x: I) -> i32 where I: IntoIterator<Item = &'a i32> {
*x.into_iter().max().unwrap()
}
let v = vec![1, 2, 3];
foo(&v)
group_by¶
The function group_by
takes a function generating keys
which are used to group elements in the iterator.
However,
notice that
groups of elements are NOT just decided by the key function
,
it
also depends on whether elements are consecutive
.
In short,
consecutive elements that map to the same key ("runs")
are assigned to the same group.
The IntoInterator Trait¶
Please refer to IntoIterator for discussions.