1

I have trouble writing code for a function that takes an iterator and returns an iterator that iterates in pairs (Option<T>, T) like so

a = [1,2,3]
assert pairwise(a) == `[(None, 1), (Some(1), 2), (Some(2), 3)]
fn pairwise<I, T>(&xs: &I) -> I
where
    I: Iterator<Item = T>,
{
    [None].iter().chain(xs.iter().map(Some)).zip(xs.iter())
}

fn main() {
    let data: Vec<i32> = vec![1, 2, 3];
    let newdata: Vec<Option<i32>, i32> = pairwise(&data).collect();
    println!("{:?}", newdata);
}
error[E0599]: no method named `iter` found for type `I` in the current scope
 --> src/main.rs:3:28
  |
3 |     [None].iter().chain(xs.iter().map(Some)).zip(xs.iter())
  |                            ^^^^
  |

Not sure why xs isn't iterable. I've stated it in the where clause haven't I?

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
user1685095
  • 5,787
  • 9
  • 51
  • 100
  • `.iter()` is for creating an iterator, but you've already got one. `xs` is already an `Iterator`. – loganfsmyth Oct 02 '17 at 22:44
  • @loganfsmyth Oh, okay. What is the type for something that has `.iter()` method? – user1685095 Oct 02 '17 at 22:45
  • I don't believe there is one. There is however an `IntoIterator` which defines the `into_iter()` method. This is automatically implemented for all `Iterator`s, so if you have an API that takes an `IntoIterator` and you don't want to actually consume the argument, the caller can just call `.iter()` themselves and pass in the resulting iterator. – Lily Ballard Oct 02 '17 at 23:22

2 Answers2

5
fn pairwise<I, T>(&xs: &I) -> I

This doesn't make sense. See What is the correct way to return an Iterator (or any other trait)? and What is the difference between `e1` and `&e2` when used as the for-loop variable?.

I: Iterator<Item = T>,

There's no reason to specify that the Item is a T.

[None].iter()

It's better to use iter::once.

xs.iter()

There's no trait in the standard library that defines an iter method. Perhaps you meant IntoIterator?

let data: Vec<i32> = vec![1, 2, 3]

There's no reason to specify the type here; i32 is the default integral type.

Vec<Option<i32>, i32>
Vec<Option<i32>, i32>> // original version

This is not a valid type for Vec, and your original form doesn't even have balanced symbols.


After all that, you are faced with tough choices. Your example code passes in an iterator which has references to the slice but you've written your assertion such that you expect to get non-references back. You've also attempted to use an arbitrary iterator twice; there's no guarantee that such a thing is viable.

The most generic form I see is:

use std::iter;

fn pairwise<I>(right: I) -> impl Iterator<Item = (Option<I::Item>, I::Item)>
where
    I: IntoIterator + Clone,
{
    let left = iter::once(None).chain(right.clone().into_iter().map(Some));
    left.zip(right)
}

fn main() {
    let data = vec![1, 2, 3];

    let newdata: Vec<_> = pairwise(&data).collect();
    assert_eq!(newdata, [(None, &1), (Some(&1), &2), (Some(&2), &3)]);

    let newdata: Vec<_> = pairwise(data.iter().copied()).collect();
    assert_eq!(newdata, [(None, 1), (Some(1), 2), (Some(2), 3)]);
}

See also:

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
  • Thanks a lot. I think I don't understand only one thing. Why is `Box` needed here? – user1685095 Oct 03 '17 at 06:11
  • 1
    @user1685095 The linked question ["What is the correct way to return an Iterator?"](https://stackoverflow.com/questions/27535289/what-is-the-correct-way-to-return-an-iterator) answers this question. – Lukas Kalbertodt Oct 03 '17 at 08:09
1

I know OP asked for "outer pairwise" ([(None, 1), (Some(1), 2), (Some(2), 3)]), but here is how I adapted it for "inner pairwise" ([(1, 2), (2, 3)]):

fn inner_pairwise<I>(right: I) -> impl Iterator<Item = (I::Item, I::Item)>
where
    I: IntoIterator + Clone,
{
    let left = right.clone().into_iter().skip(1);
    left.zip(right)
}

For anyone here for "inner pairwise", you're looking for Itertools::tuple_windows.

Marcel
  • 1,034
  • 1
  • 17
  • 35