Things on this page are fragmentary and immature notes/thoughts of the author. Please read with your own judgement!
:timing
:sccache 1Tips & 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.
iter vs into_iter¶
What is the difference between iter and into_iter?
Why does iter() and into_iter() does the same thing if the object is a reference?
filter¶
v1.iter().filter(|&&x| x > 0).count()9v1.iter().max().unwrap()30*v1.iter().max().unwrap()30v1.iter().filter(|x| x > 0).count()v1.iter().filter(|x| x > 0).count()
^ expected `&&i32`, found integer
mismatched typesmap¶
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[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]v.iter().take(3)Take { iter: Iter([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]), n: 3 }v.iter().take(3).collect::<Vec<_>>()[0, 1, 2]v.iter().take_while(|&&x| x < 3)TakeWhile { iter: Iter([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]), flag: false }v.iter().take_while(|&&x| x < 3).collect::<Vec<_>>()[0, 1, 2]v.iter().skip(6)Skip { iter: Iter([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]), n: 6 }v.iter().skip(6).collect::<Vec<_>>()[6, 7, 8, 9]v.iter().skip_while(|&&x| x < 6)SkipWhile { iter: Iter([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]), flag: false }v.iter().skip_while(|&&x| x < 6).collect::<Vec<_>>()[6, 7, 8, 9]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);alphabetagamma
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);let merged: String = words.into_iter().collect();
^^^^^^^ value of type `String` cannot be built from `std::iter::Iterator<Item=&&str>`
a value of type `String` cannot be built from an iterator over elements of type `&&str`
help: the trait `FromIterator<&&str>` is not implemented for `String`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);alphabetagamma
The itertools Crate¶
The Rust crate itertools provides additional functionalities in addtion to those provided by the standard library.
: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 merged: String = words.into_iter().intersperse(", ").collect();
^^^^^^^^^^^
an associated function with this name may be added to the standard library in the future
help: call with fully qualified syntax `itertools::Itertools::intersperse(...)` to keep using the current methodlet merged: String = words.into_iter().intersperse(", ").collect();
^^^^ expected `&str`, found `str`
mismatched typeslet merged: String = words.into_iter().intersperse(", ").collect();
^^^^^^^ value of type `String` cannot be built from `std::iter::Iterator<Item=&&str>`
a value of type `String` cannot be built from an iterator over elements of type `&&str`
help: the trait `FromIterator<&&str>` is not implemented for `String`let words = ["alpha", "beta", "gamma"];
let merged: String = words.iter().copied().intersperse(", ").collect();
println!("{}", merged);alpha, beta, gamma
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())find_min(s.iter())
^^^^^^^^ expected `str`, found `&str`
type mismatch resolving `<std::slice::Iter<'_, &str> as Iterator>::Item == &'static str`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)Some("how")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)3group_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.