Rust library to provide .filter_with() and .filter_map_with() methods for Iterator objects
This is a tiny library to provide filter_with
and filter_map_with
methods for Iterator
.
filter_with
is almost the same as filter
,
but the difference is that filter_with
can have a state while filtering.
fn filter_with<I, S, P>(self: I, state: S, predicate: P) -> FilterWith<I, P, S>
where
I: Iterator + Sized
P: FnMut(&mut S, &Self::Item) -> bool
And filter_map_with
is almost same as filter_map
but it can have state.
To make explanation simple and (a bit) practical, let’s say to write a code to implement unique
operation. unique
removes all duplicates from a sequence like Vec
.
It can be easily implemented in Rust with filter
method of Iterator
and &mut
borrow. HashSet
can be used to check element’s uniqueness.
[1, 2, 1, 1, 2, 2, 3]
[1, 2, 3]
use std::collections::HashSet;
let mut state = HashSet::new();
let v = vec![1, 2, 1, 1, 2, 2, 3];
let v2 = v
.iter()
.filter(|i| {
if state.contains(*i) {
false
} else {
state.insert(**i);
true
}
})
.collect::<Vec<_>>();
// Shows [1, 2, 3]
println!("{:?}", v2);
Next, let’s say to create a unique sequences and flatten them from sequence of sequence.
[[1, 2, 1], [1, 2, 2, 3]]
[1, 2, 1, 2, 3]
(flattened [[1, 2], [1, 2, 3]]
)You may write a code like
use std::collections::HashSet;
let vv = vec![vec![1, 2, 1], vec![1, 2, 2, 3]];
let v2 = vv
.iter()
.map(|v| {
let mut state = HashSet::new();
v.iter().filter(|i| {
if state.contains(*i) {
false
} else {
state.insert(**i);
true
}
})
})
.flatten()
.collect::<Vec<_>>();
println!("{:?}", v2);
But it does not work since state
variable dies at the end of closure passed to .map()
, but the
returned iterator in the closure must live until .collect::<Vec<_>>()
is called. state
variable
does not live long enough.
By using filter_with
, this issue can be solved as follows.
use std::collections::HashSet;
use filter_with_state::IteratorExt;
let vv = vec![vec![1, 2, 1], vec![1, 2, 2, 3]];
let v2 = vv
.iter()
.map(|v| {
v.iter().filter_with(HashSet::new(), |state, i| {
if state.contains(*i) {
false
} else {
state.insert(**i);
true
}
})
})
.flatten()
.collect::<Vec<_>>();
println!("{:?}", v2);
The state
is stored in an iterator struct FilterWith
. So it has the same lifetime as its iterator.
struct FilterWith<I, S, P> {
iter: I,
state: S,
predicate: P,
}
Add filter_with_state
crate to your crate’s dependencies.
filter_with_state = "0.x"
Please add use filter_with_state::IteratorExt
to add filter_with
and filter_map_with
methods
to Iterator
trait.
{
use filter_with_state::IteratorExt;
// Here Iterator objects have .fiter_with() and .filter_map_with() methods
}