diff --git a/src/adaptors/mod.rs b/src/adaptors/mod.rs index 52ee4800c..3528e3b23 100644 --- a/src/adaptors/mod.rs +++ b/src/adaptors/mod.rs @@ -16,7 +16,7 @@ pub use self::multi_product::*; use crate::size_hint::{self, SizeHint}; use std::fmt; -use std::iter::{FromIterator, Fuse, FusedIterator}; +use std::iter::{Enumerate, FromIterator, Fuse, FusedIterator}; use std::marker::PhantomData; /// An iterator adaptor that alternates elements from two iterators until both @@ -1039,16 +1039,15 @@ where #[derive(Clone)] #[must_use = "iterator adaptors are lazy and do nothing unless consumed"] pub struct Positions { - iter: I, + iter: Enumerate, f: F, - count: usize, } impl fmt::Debug for Positions where I: fmt::Debug, { - debug_fmt_fields!(Positions, iter, count); + debug_fmt_fields!(Positions, iter); } /// Create a new `Positions` iterator. @@ -1057,7 +1056,8 @@ where I: Iterator, F: FnMut(I::Item) -> bool, { - Positions { iter, f, count: 0 } + let iter = iter.enumerate(); + Positions { iter, f } } impl Iterator for Positions @@ -1068,14 +1068,10 @@ where type Item = usize; fn next(&mut self) -> Option { - while let Some(v) = self.iter.next() { - let i = self.count; - self.count = i + 1; - if (self.f)(v) { - return Some(i); - } - } - None + let f = &mut self.f; + // TODO: once MSRV >= 1.62, use `then_some`. + self.iter + .find_map(|(count, val)| if f(val) { Some(count) } else { None }) } fn size_hint(&self) -> (usize, Option) { @@ -1086,13 +1082,11 @@ where where G: FnMut(B, Self::Item) -> B, { - let mut count = self.count; let mut f = self.f; - self.iter.fold(init, |mut acc, val| { + self.iter.fold(init, |mut acc, (count, val)| { if f(val) { acc = func(acc, count); } - count += 1; acc }) } @@ -1104,22 +1098,20 @@ where F: FnMut(I::Item) -> bool, { fn next_back(&mut self) -> Option { - while let Some(v) = self.iter.next_back() { - if (self.f)(v) { - return Some(self.count + self.iter.len()); - } - } - None + let f = &mut self.f; + // TODO: once MSRV >= 1.62, use `then_some`. + self.iter + .by_ref() + .rev() + .find_map(|(count, val)| if f(val) { Some(count) } else { None }) } fn rfold(self, init: B, mut func: G) -> B where G: FnMut(B, Self::Item) -> B, { - let mut count = self.count + self.iter.len(); let mut f = self.f; - self.iter.rfold(init, |mut acc, val| { - count -= 1; + self.iter.rfold(init, |mut acc, (count, val)| { if f(val) { acc = func(acc, count); } diff --git a/src/lib.rs b/src/lib.rs index bdb436e48..9a4043095 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1806,7 +1806,7 @@ pub trait Itertools: Iterator { /// Return an iterator adaptor that yields the indices of all elements /// satisfying a predicate, counted from the start of the iterator. /// - /// Equivalent to `iter.enumerate().filter(|(_, v)| predicate(v)).map(|(i, _)| i)`. + /// Equivalent to `iter.enumerate().filter(|(_, v)| predicate(*v)).map(|(i, _)| i)`. /// /// ``` /// use itertools::Itertools; diff --git a/tests/quick.rs b/tests/quick.rs index 6f45a63d0..92d3f9f8e 100644 --- a/tests/quick.rs +++ b/tests/quick.rs @@ -604,6 +604,12 @@ quickcheck! { let b = &b[..len]; itertools::equal(zip_eq(a, b), zip(a, b)) } + fn equal_positions(a: Vec) -> bool { + let with_pos = a.iter().positions(|v| v % 2 == 0); + let without = a.iter().enumerate().filter(|(_, v)| *v % 2 == 0).map(|(i, _)| i); + itertools::equal(with_pos.clone(), without.clone()) + && itertools::equal(with_pos.rev(), without.rev()) + } fn size_zip_longest(a: Iter, b: Iter) -> bool { let filt = a.clone().dedup(); let filt2 = b.clone().dedup();