项目作者: rhysd

项目描述 :
Rust library to provide .filter_with() and .filter_map_with() methods for Iterator objects
高级语言: Rust
项目地址: git://github.com/rhysd/filter-with-state.git
创建时间: 2019-01-05T13:44:38Z
项目社区:https://github.com/rhysd/filter-with-state

开源协议:MIT License

下载


Filtering given iterator with state

Build Status

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.

  1. fn filter_with<I, S, P>(self: I, state: S, predicate: P) -> FilterWith<I, P, S>
  2. where
  3. I: Iterator + Sized
  4. P: FnMut(&mut S, &Self::Item) -> bool

And filter_map_with is almost same as filter_map
but it can have state.

Why this library is necessary

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.

  • Given: [1, 2, 1, 1, 2, 2, 3]
  • Want: [1, 2, 3]
  1. use std::collections::HashSet;
  2. let mut state = HashSet::new();
  3. let v = vec![1, 2, 1, 1, 2, 2, 3];
  4. let v2 = v
  5. .iter()
  6. .filter(|i| {
  7. if state.contains(*i) {
  8. false
  9. } else {
  10. state.insert(**i);
  11. true
  12. }
  13. })
  14. .collect::<Vec<_>>();
  15. // Shows [1, 2, 3]
  16. println!("{:?}", v2);

Next, let’s say to create a unique sequences and flatten them from sequence of sequence.

  • Given: [[1, 2, 1], [1, 2, 2, 3]]
  • Want: [1, 2, 1, 2, 3] (flattened [[1, 2], [1, 2, 3]])

You may write a code like

  1. use std::collections::HashSet;
  2. let vv = vec![vec![1, 2, 1], vec![1, 2, 2, 3]];
  3. let v2 = vv
  4. .iter()
  5. .map(|v| {
  6. let mut state = HashSet::new();
  7. v.iter().filter(|i| {
  8. if state.contains(*i) {
  9. false
  10. } else {
  11. state.insert(**i);
  12. true
  13. }
  14. })
  15. })
  16. .flatten()
  17. .collect::<Vec<_>>();
  18. 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.

  1. use std::collections::HashSet;
  2. use filter_with_state::IteratorExt;
  3. let vv = vec![vec![1, 2, 1], vec![1, 2, 2, 3]];
  4. let v2 = vv
  5. .iter()
  6. .map(|v| {
  7. v.iter().filter_with(HashSet::new(), |state, i| {
  8. if state.contains(*i) {
  9. false
  10. } else {
  11. state.insert(**i);
  12. true
  13. }
  14. })
  15. })
  16. .flatten()
  17. .collect::<Vec<_>>();
  18. println!("{:?}", v2);

The state is stored in an iterator struct FilterWith. So it has the same lifetime as its iterator.

  1. struct FilterWith<I, S, P> {
  2. iter: I,
  3. state: S,
  4. predicate: P,
  5. }

Installation

Add filter_with_state crate to your crate’s dependencies.

  1. filter_with_state = "0.x"

Usage

Please add use filter_with_state::IteratorExt to add filter_with and filter_map_with methods
to Iterator trait.

  1. {
  2. use filter_with_state::IteratorExt;
  3. // Here Iterator objects have .fiter_with() and .filter_map_with() methods
  4. }