Rust:重复另一个迭代器的第一个和最后一个元素的迭代器?

v2g6jxz6  于 2023-05-18  发布在  其他
关注(0)|答案(3)|浏览(204)

是否存在Iterator,无论是在std或维护的crate中,它重复另一个Iterator的第一个和最后一个元素,如果ItemClone
示例:

let iter = [1, 2, 3].into_iter();

assert!(iter.repeat_first_and_last().eq([1, 1, 2, 3, 3]));
axr492tv

axr492tv1#

你也可以选择自己的,如果你想:

use std::iter::Fuse;

pub struct FirstLastRepeat<I, T> {
    iter: Fuse<I>,
    head: Option<T>,
    tail: Option<T>,
    stash: Option<T>,
}

impl<I, T> FirstLastRepeat<I, T>
where
    I: Iterator<Item = T>,
{
    pub fn new(iter: I) -> Self {
        let mut iter = iter.fuse();
        let head = iter.next();
        Self {
            iter,
            head,
            tail: None,
            stash: None,
        }
    }
}

impl<I, T> Iterator for FirstLastRepeat<I, T>
where
    I: Iterator<Item = T>,
    T: Clone,
{
    type Item = T;

    fn next(&mut self) -> Option<Self::Item> {
        if let v @ Some(_) = self.head.take() {
            self.stash = v.clone();
            return v;
        }
        if let v @ Some(_) = self.tail.take() {
            return v;
        }
        let next = self.stash.take();
        match self.iter.next() {
            v @ Some(_) => self.stash = v,
            None => self.tail = next.clone(),
        }
        next
    }
}

#[test]
fn basic() {
    let iter = [1, 2, 3].into_iter();
    let flr = FirstLastRepeat::new(iter);

    assert!(flr.eq([1, 1, 2, 3, 3]));
}

这里唯一奇怪的边缘情况是只有一个元素的原始迭代器。目前还不清楚这里正确的行为是什么,但FristLastRepeat将产生三次,这似乎在任何情况下都不正确。不过,这是可以解决的。

tyu7yeag

tyu7yeag2#

我不知道在stditertools中有什么方法可以做到这一点。你可以合并多个迭代器方法来实现这一点,不过:

use std::iter::repeat;

fn main() {
    let iter = [1, 2, 3, 4].into_iter();
    let len = iter.len();

    let res: Vec<u8> = iter
        .enumerate()
        .map(|(i, x)| repeat(x).take((i == 0 || i == len - 1).then(|| 2).unwrap_or(1)))
        .flatten()
        .collect();

    assert_eq!(res, vec![1, 1, 2, 3, 4, 4]);
}

Playground.
请注意,重复最后一个元素两次需要我们事先知道迭代器的大小,因此迭代器类型必须实现ExactSizeIterator,或者必须提供一些其他方法来获得长度。

qaxu7uf2

qaxu7uf23#

最后我自己卷了起来。这比isaactfa的方法稍微好一点,因为它不需要FusedIterator,而且代码量也差不多。

use std::mem::take;

use tap::Tap;

struct Padded<T: Iterator> {
    inner: T,
    repeat_first: bool,
    repeat_last: bool,
    next: Option<T::Item>,
}

impl<T: Iterator> Padded<T>
where
    T::Item: Clone,
{
    fn new(inner: impl IntoIterator<IntoIter = T>) -> Self
    where
        T::Item: Clone,
    {
        let mut inner = inner.into_iter();
        let next = inner.next();
        
        Self { inner, next, repeat_first: true, repeat_last: true, }
    }
}

impl<T: Iterator> Iterator for Padded<T>
where
    T::Item: Clone,
{
    type Item = T::Item;

    fn next(&mut self) -> Option<Self::Item> {
        self.next.take().tap(|next| {
            if take(&mut self.repeat_first) {
                self.next = next.clone();
            } else {
                self.next = self.inner.next().or_else(|| {
                    next.as_ref().filter(|_| take(&mut self.repeat_last)).cloned()
                })
            }
        })
    }
}

fn main() {
    Padded::new([1, 2, 3]).for_each(|n| print!("{n}"));
}

相关问题