Skip to content

Commit 3433851

Browse files
committed
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.
2 parents 4e5b480 + 6291702 commit 3433851

File tree

1 file changed

+67
-0
lines changed

1 file changed

+67
-0
lines changed

Diff for: src/libstd/iterator.rs

+67
Original file line numberDiff line numberDiff line change
@@ -225,6 +225,26 @@ pub trait IteratorUtil<A> {
225225
fn scan<'r, St, B>(self, initial_state: St, f: &'r fn(&mut St, A) -> Option<B>)
226226
-> ScanIterator<'r, A, B, Self, St>;
227227

228+
/// Creates an iterator that maps each element to an iterator,
229+
/// and yields the elements of the produced iterators
230+
///
231+
/// # Example
232+
///
233+
/// ~~~ {.rust}
234+
/// let xs = [2u, 3];
235+
/// let ys = [0u, 1, 0, 1, 2];
236+
/// let mut it = xs.iter().flat_map_(|&x| Counter::new(0u, 1).take_(x));
237+
/// // Check that `it` has the same elements as `ys`
238+
/// let mut i = 0;
239+
/// for it.advance |x: uint| {
240+
/// assert_eq!(x, ys[i]);
241+
/// i += 1;
242+
/// }
243+
/// ~~~
244+
// FIXME: #5898: should be called `flat_map`
245+
fn flat_map_<'r, B, U: Iterator<B>>(self, f: &'r fn(A) -> U)
246+
-> FlatMapIterator<'r, A, B, Self, U>;
247+
228248
/// An adaptation of an external iterator to the for-loop protocol of rust.
229249
///
230250
/// # Example
@@ -396,6 +416,12 @@ impl<A, T: Iterator<A>> IteratorUtil<A> for T {
396416
ScanIterator{iter: self, f: f, state: initial_state}
397417
}
398418

419+
#[inline]
420+
fn flat_map_<'r, B, U: Iterator<B>>(self, f: &'r fn(A) -> U)
421+
-> FlatMapIterator<'r, A, B, T, U> {
422+
FlatMapIterator{iter: self, f: f, subiter: None }
423+
}
424+
399425
/// A shim implementing the `for` loop iteration protocol for iterator objects
400426
#[inline]
401427
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,
868894
}
869895
}
870896

897+
/// An iterator that maps each element to an iterator,
898+
/// and yields the elements of the produced iterators
899+
///
900+
// FIXME #6967: Dummy B parameter to get around type inference bug
901+
pub struct FlatMapIterator<'self, A, B, T, U> {
902+
priv iter: T,
903+
priv f: &'self fn(A) -> U,
904+
priv subiter: Option<U>,
905+
}
906+
907+
impl<'self, A, T: Iterator<A>, B, U: Iterator<B>> Iterator<B> for
908+
FlatMapIterator<'self, A, B, T, U> {
909+
#[inline]
910+
fn next(&mut self) -> Option<B> {
911+
loop {
912+
for self.subiter.mut_iter().advance |inner| {
913+
for inner.advance |x| {
914+
return Some(x)
915+
}
916+
}
917+
match self.iter.next().map_consume(self.f) {
918+
None => return None,
919+
next => self.subiter = next,
920+
}
921+
}
922+
}
923+
}
924+
871925
/// An iterator which just modifies the contained state throughout iteration.
872926
pub struct UnfoldrIterator<'self, A, St> {
873927
priv f: &'self fn(&mut St) -> Option<A>,
@@ -1046,6 +1100,19 @@ mod tests {
10461100
assert_eq!(i, ys.len());
10471101
}
10481102

1103+
#[test]
1104+
fn test_iterator_flat_map() {
1105+
let xs = [0u, 3, 6];
1106+
let ys = [0u, 1, 2, 3, 4, 5, 6, 7, 8];
1107+
let mut it = xs.iter().flat_map_(|&x| Counter::new(x, 1).take_(3));
1108+
let mut i = 0;
1109+
for it.advance |x: uint| {
1110+
assert_eq!(x, ys[i]);
1111+
i += 1;
1112+
}
1113+
assert_eq!(i, ys.len());
1114+
}
1115+
10491116
#[test]
10501117
fn test_unfoldr() {
10511118
fn count(st: &mut uint) -> Option<uint> {

0 commit comments

Comments
 (0)