diff options
| author | bors <bors@rust-lang.org> | 2013-06-26 09:47:16 -0700 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2013-06-26 09:47:16 -0700 |
| commit | 3433851a37f04621e0c091ec2180aeddbdd5ada5 (patch) | |
| tree | 521ab48bddd3bc26043cfcaa23db5b85cf8ab8c5 /src/libstd | |
| parent | 4e5b4807a5b620627cf6e782524fbe6fc1463c2d (diff) | |
| parent | 6291702cf334f4b1fe41662bc3b0d996ca7ced19 (diff) | |
| download | rust-3433851a37f04621e0c091ec2180aeddbdd5ada5.tar.gz rust-3433851a37f04621e0c091ec2180aeddbdd5ada5.zip | |
auto merge of #7345 : blake2-ppc/rust/iterator-flat-map, r=thestinger
flat_map_ produces an iterator that maps each element to an iterator, and yields the elements of the produced iterators. This is the monadic bind :: M a -> (a -> M b) -> M b for iterators. Named just like the vec method, but with a trailing underline until the method resolution bug is resolved. We discussed the name chain_map, but I decided to go with flat_map_ for consistency with vec. Since it.map(f).flatten() would be the same as it.flat_map(f), we could choose to just implement a flatten method instead. Either way the possibilities are the same but flat_map is more convenient.
Diffstat (limited to 'src/libstd')
| -rw-r--r-- | src/libstd/iterator.rs | 67 |
1 files changed, 67 insertions, 0 deletions
diff --git a/src/libstd/iterator.rs b/src/libstd/iterator.rs index 9177ecabed6..ab433a9a79d 100644 --- a/src/libstd/iterator.rs +++ b/src/libstd/iterator.rs @@ -225,6 +225,26 @@ pub trait IteratorUtil<A> { fn scan<'r, St, B>(self, initial_state: St, f: &'r fn(&mut St, A) -> Option<B>) -> ScanIterator<'r, A, B, Self, St>; + /// Creates an iterator that maps each element to an iterator, + /// and yields the elements of the produced iterators + /// + /// # Example + /// + /// ~~~ {.rust} + /// let xs = [2u, 3]; + /// let ys = [0u, 1, 0, 1, 2]; + /// let mut it = xs.iter().flat_map_(|&x| Counter::new(0u, 1).take_(x)); + /// // Check that `it` has the same elements as `ys` + /// let mut i = 0; + /// for it.advance |x: uint| { + /// assert_eq!(x, ys[i]); + /// i += 1; + /// } + /// ~~~ + // FIXME: #5898: should be called `flat_map` + fn flat_map_<'r, B, U: Iterator<B>>(self, f: &'r fn(A) -> U) + -> FlatMapIterator<'r, A, B, Self, U>; + /// An adaptation of an external iterator to the for-loop protocol of rust. /// /// # Example @@ -396,6 +416,12 @@ impl<A, T: Iterator<A>> IteratorUtil<A> for T { ScanIterator{iter: self, f: f, state: initial_state} } + #[inline] + fn flat_map_<'r, B, U: Iterator<B>>(self, f: &'r fn(A) -> U) + -> FlatMapIterator<'r, A, B, T, U> { + FlatMapIterator{iter: self, f: f, subiter: None } + } + /// A shim implementing the `for` loop iteration protocol for iterator objects #[inline] fn advance(&mut self, f: &fn(A) -> bool) -> bool { @@ -868,6 +894,34 @@ impl<'self, A, B, T: Iterator<A>, St> Iterator<B> for ScanIterator<'self, A, B, } } +/// An iterator that maps each element to an iterator, +/// and yields the elements of the produced iterators +/// +// FIXME #6967: Dummy B parameter to get around type inference bug +pub struct FlatMapIterator<'self, A, B, T, U> { + priv iter: T, + priv f: &'self fn(A) -> U, + priv subiter: Option<U>, +} + +impl<'self, A, T: Iterator<A>, B, U: Iterator<B>> Iterator<B> for + FlatMapIterator<'self, A, B, T, U> { + #[inline] + fn next(&mut self) -> Option<B> { + loop { + for self.subiter.mut_iter().advance |inner| { + for inner.advance |x| { + return Some(x) + } + } + match self.iter.next().map_consume(self.f) { + None => return None, + next => self.subiter = next, + } + } + } +} + /// An iterator which just modifies the contained state throughout iteration. pub struct UnfoldrIterator<'self, A, St> { priv f: &'self fn(&mut St) -> Option<A>, @@ -1047,6 +1101,19 @@ mod tests { } #[test] + fn test_iterator_flat_map() { + let xs = [0u, 3, 6]; + let ys = [0u, 1, 2, 3, 4, 5, 6, 7, 8]; + let mut it = xs.iter().flat_map_(|&x| Counter::new(x, 1).take_(3)); + let mut i = 0; + for it.advance |x: uint| { + assert_eq!(x, ys[i]); + i += 1; + } + assert_eq!(i, ys.len()); + } + + #[test] fn test_unfoldr() { fn count(st: &mut uint) -> Option<uint> { if *st < 10 { |
