如何使用滑动 window 对生成迭代器?

How to generate iterator with sliding window pairs?

我想为这个输入创建一个迭代器:

[1, 2, 3, 4]

将包含以下内容:

(1, 2)
(2, 3)
(3, 4)

Peekable 似乎很适合这个,但我是 Rust 的新手,所以这个天真的版本不起作用:

fn main() {
  let i = ['a', 'b', 'c']
    .iter()
    .peekable();
  let j = i.map(|x| (x, i.peek()));
  println!("{:?}", j);
  println!("Hello World!");
}

我做错了什么?

可以对切片使用windows方法,然后将数组映射成元组:

fn main() {
    let i = [1, 2, 3, 4]
        .windows(2)
        .map(|pair| (pair[0], pair[1]));
    println!("{:?}", i.collect::<Vec<_>>());
}

playground


如果您想要一个适用于所有迭代器(而不仅仅是切片)的解决方案并且愿意使用第 3 方库,您可以使用 itertools 中的 tuple_windows 方法。

use itertools::{Itertools, TupleWindows}; // 0.10.0

fn main() {
    let i: TupleWindows<_, (i32, i32)> = vec![1, 2, 3, 4]
        .into_iter()
        .tuple_windows();
    println!("{:?}", i.collect::<Vec<_>>());
}

playground


如果你不愿意使用第三方库,那么你自己实现它仍然很简单!这是一个适用于任何 Iterator<Item = T> 的示例通用实现,其中 T: Clone:

use std::collections::BTreeSet;

struct PairIter<I, T>
where
    I: Iterator<Item = T>,
    T: Clone,
{
    iterator: I,
    last_item: Option<T>,
}

impl<I, T> PairIter<I, T>
where
    I: Iterator<Item = T>,
    T: Clone,
{
    fn new(iterator: I) -> Self {
        PairIter {
            iterator,
            last_item: None,
        }
    }
}

impl<I, T> Iterator for PairIter<I, T>
where
    I: Iterator<Item = T>,
    T: Clone,
{
    type Item = (T, T);
    fn next(&mut self) -> Option<Self::Item> {
        if self.last_item.is_none() {
            self.last_item = self.iterator.next();
        }
        if self.last_item.is_none() {
            return None;
        }
        let curr_item = self.iterator.next();
        if curr_item.is_none() {
            return None;
        }
        let temp_item = curr_item.clone();
        let result = (self.last_item.take().unwrap(), curr_item.unwrap());
        self.last_item = temp_item;
        Some(result)
    }
}

fn example<T: Clone>(iterator: impl Iterator<Item = T>) -> impl Iterator<Item = (T, T)> {
    PairIter::new(iterator)
}

fn main() {
    let mut set = BTreeSet::new();
    set.insert(String::from("a"));
    set.insert(String::from("b"));
    set.insert(String::from("c"));
    set.insert(String::from("d"));
    dbg!(example(set.into_iter()).collect::<Vec<_>>());
}

playground

您可以使用 itertools 箱子中的 tuple_windows() 作为直接替代品:

use itertools::Itertools;

fn main() {
    let data = vec![1, 2, 3, 4];
    for (a, b) in data.iter().tuple_windows() {
        println!("({}, {})", a, b);
    }
}
(1, 2)
(2, 3)
(3, 4)