Skip to content

Add Pair adaptor for Iterator to return elements two at a time #14528

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 1 commit into from
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
75 changes: 75 additions & 0 deletions src/libcore/iter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -386,6 +386,41 @@ pub trait Iterator<A> {
Fuse{iter: self, done: false}
}

/// Creates an iterator that yields pairs ef elements from the underlying
/// iterator, yielding `None` when there are fewer than two elements to
/// return.
///
/// # Example
///
/// ```rust
/// let xs = "10ab20cde".chars().pair();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is this let-binding doing here?

/// fn hex(data: &str) -> Option<Vec<u8>> {
/// let hex = "0123456789abcdef";
/// let mut char_iter = data.chars().pair();
/// let mut ret = vec![];
///
/// // Convert pairs of base-16 digits at a time to bytes
/// for (f, s) in char_iter {
/// let fx = hex.find(f.to_lowercase());
/// let sx = hex.find(s.to_lowercase());
/// if fx.is_none() || sx.is_none() {
/// return None;
/// }
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a very inefficient way of dealing with hex, especially because char already has methods of testing and converting hex digits (see to_digit())

/// ret.push((fx.unwrap() * 0x10 + sx.unwrap()) as u8);
/// }
///
/// // If there is a remaining element, fail decode
/// match char_iter.remainder() {
/// None => Some(ret),
/// Some(_) => None
/// }
/// }
/// ```
#[inline]
fn pair(self) -> Pair<A, Self> {
Pair{iter: self, last_elem: None}
}

/// Creates an iterator that calls a function with a reference to each
/// element before yielding it. This is often useful for debugging an
/// iterator pipeline.
Expand Down Expand Up @@ -1817,6 +1852,46 @@ impl<T> Fuse<T> {
}
}

/// An iterator that returns pairs of elements
pub struct Pair<A, T> {
iter: T,
last_elem: Option<A>
}

impl<A, T: Iterator<A>> Iterator<(A, A)> for Pair<A, T> {
#[inline]
fn next(&mut self) -> Option<(A, A)> {
let elem1 = self.iter.next();
let elem2 = self.iter.next();
if elem1.is_none() {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You should bail if elem1.is_none() before even calling next() a second time. This will behave better if you're wrapping some other iterator that actually has defined behavior after returning None.

None
} else if elem2.is_none() {
self.last_elem = elem2;
None
} else {
Some((elem1.unwrap(), elem2.unwrap()))
}
}

#[inline]
fn size_hint(&self) -> (uint, Option<uint>) {
match self.iter.size_hint() {
(n, None) => (n/2, None),
(n, Some(m)) => (n/2, Some(m/2))
}
}
}

impl<A, T: Iterator<A>> Pair<A, T> {
/// Returns the last element of the iterator if there were an odd
/// number of elements remaining before it was Pair-ified.
#[inline]
pub fn remainder(self) -> Option<A> {
self.last_elem
}
}


/// An iterator that calls a function with a reference to each
/// element before yielding it.
pub struct Inspect<'a, A, T> {
Expand Down