diff --git a/corelib/src/iter/adapters.cairo b/corelib/src/iter/adapters.cairo index e938418f280..5a1a3853773 100644 --- a/corelib/src/iter/adapters.cairo +++ b/corelib/src/iter/adapters.cairo @@ -17,3 +17,8 @@ mod peekable; #[allow(unused_imports)] pub(crate) use peekable::peekable_iterator; pub use peekable::{Peekable, PeekableTrait}; + +mod filter; +pub use filter::Filter; +#[allow(unused_imports)] +pub(crate) use filter::filter_iterator; diff --git a/corelib/src/iter/adapters/filter.cairo b/corelib/src/iter/adapters/filter.cairo new file mode 100644 index 00000000000..896fad3c8fd --- /dev/null +++ b/corelib/src/iter/adapters/filter.cairo @@ -0,0 +1,31 @@ +/// An iterator that filters the elements of `iter` with `predicate`. +/// +/// This `struct` is created by the [`filter`] method on [`Iterator`]. See its +/// documentation for more. +/// +/// [`filter`]: Iterator::filter +#[must_use] +#[derive(Drop, Clone)] +pub struct Filter { + pub iter: I, + pub predicate: P, +} + +pub fn filter_iterator(iter: I, predicate: P) -> Filter { + Filter { iter, predicate } +} + +impl FilterIterator< + I, + P, + impl TIter: Iterator, + +core::ops::Fn[Output: bool], + +Destruct, + +Destruct

, + +Destruct, +> of Iterator> { + type Item = TIter::Item; + fn next(ref self: Filter) -> Option { + self.iter.find(@self.predicate) + } +} diff --git a/corelib/src/iter/traits/iterator.cairo b/corelib/src/iter/traits/iterator.cairo index 0bd351f48b0..308432c787f 100644 --- a/corelib/src/iter/traits/iterator.cairo +++ b/corelib/src/iter/traits/iterator.cairo @@ -1,6 +1,6 @@ use crate::iter::adapters::{ - Enumerate, Map, Peekable, Zip, enumerated_iterator, mapped_iterator, peekable_iterator, - zipped_iterator, + Enumerate, Filter, Map, Peekable, Zip, enumerated_iterator, filter_iterator, mapped_iterator, + peekable_iterator, zipped_iterator, }; use crate::iter::traits::{Product, Sum}; @@ -364,6 +364,8 @@ pub trait Iterator { /// // we can still use `iter`, as there are more elements. /// assert_eq!(iter.next(), Option::Some(3)); /// ``` + /// + /// Note that `iter.find(f)` is equivalent to `iter.filter(f).next()`. fn find< P, +core::ops::Fn[Output: bool], @@ -385,6 +387,41 @@ pub trait Iterator { } } + /// Creates an iterator which uses a closure to determine if an element + /// should be yielded. The closure takes each element as a snapshot. + /// + /// Given an element the closure must return `true` or `false`. The returned + /// iterator will yield only the elements for which the closure returns + /// `true`. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// let a = array![0_u32, 1, 2]; + /// + /// let mut iter = a.into_iter().filter(|x| *x > 0); + /// + /// assert_eq!(iter.next(), Option::Some(1)); + /// assert_eq!(iter.next(), Option::Some(2)); + /// assert_eq!(iter.next(), Option::None); + /// ``` + /// + /// Note that `iter.filter(f).next()` is equivalent to `iter.find(f)`. + #[inline] + fn filter< + P, + +core::ops::Fn[Output: bool], + +Destruct

, + +Destruct, + +Destruct, + >( + self: T, predicate: P, + ) -> Filter { + filter_iterator(self, predicate) + } + /// 'Zips up' two iterators into a single iterator of pairs. /// /// `zip()` returns a new iterator that will iterate over two other diff --git a/corelib/src/test/iter_test.cairo b/corelib/src/test/iter_test.cairo index 2a176836b0a..d3189a51d0e 100644 --- a/corelib/src/test/iter_test.cairo +++ b/corelib/src/test/iter_test.cairo @@ -121,3 +121,11 @@ fn test_iter_find() { assert_eq!(iter.find(|x| *x == 2), Option::Some(2)); assert_eq!(iter.next(), Option::Some(3)); } + +#[test] +fn test_iter_adapter_filter() { + let mut iter = array![0_u32, 1, 2].into_iter().filter(|x| *x > 0); + assert_eq!(iter.next(), Option::Some(1)); + assert_eq!(iter.next(), Option::Some(2)); + assert_eq!(iter.next(), Option::None); +}