Search code examples
iteratorrust

Implement a pairwise iterator


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?


Solution

  • 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: