【问题标题】:How can I skip the Nth element in a Rust iterator?如何跳过 Rust 迭代器中的第 N 个元素?
【发布时间】:2026-02-07 16:05:01
【问题描述】:

迭代器有一个 skip 方法跳过第一个 n 元素:

let list = vec![1, 2, 3];
let iterator = list.iter();
let skip_iter = iterator.skip(2); //skip the first 2 elements

我找不到只跳过迭代器中的n-th 元素的方法。我需要自己实现一些东西,还是有我没有找到的方法?

【问题讨论】:

  • 我认为没有特定的方法可以做到这一点,但您可以enumerate().filter(|(i, v)| (i + 1) != n).map(|(i, v)| v) 跳过nth 元素。

标签: iterator rust skip


【解决方案1】:

这似乎是一个非常具体的操作。标准库或itertools crate 中没有适配器。

尽管如此,它很容易实现。可以枚举每个元素并过滤索引:

iter.enumerate().filter(|&(i, _)| i != n).map(|(_, v)| v)

Playground

【讨论】:

    【解决方案2】:

    我偏爱filter_map 版本

    fn main() {
        let v = vec![1, 2, 3];
        let n = 1;
        let x: Vec<_> = v.into_iter()
            .enumerate()
            .filter_map(|(i, e)| if i != n { Some(e) } else { None })
            .collect();
        println!("{:?}", x);
    }
    

    Playground

    【讨论】:

    • 这对.filter(..)有什么好处?似乎更长的时间没有收获。
    • 只使用filter 的解决方案返回包含索引的元组,这将返回没有索引的底层元素。这取决于你想要什么结果
    【解决方案3】:

    我已经想跳过某个范围。我认为最好的方法是创建一个迭代器:

    mod skip_range {
        use std::ops::Range;
        use std::iter::Skip;
    
        /// Either the user provided iterator, or a `Skip` one.
        enum Either<I: Iterator> {
            Iter(I),
            Skip(Skip<I>),
        }
    
        pub struct SkipRange<I: Iterator> {
            it: Option<Either<I>>,
            count: usize,
            range: Range<usize>,
        }
    
        impl<I: Iterator> SkipRange<I> {
            pub fn new(it: I, range: Range<usize>) -> Self {
                SkipRange { it: Some(Either::Iter(it)), count: 0, range }
            }
        }
    
        impl<I: Iterator> Iterator for SkipRange<I> {
            type Item = I::Item;
    
            fn next(&mut self) -> Option<Self::Item> {
                // If we are in the part we must skip, change the iterator to `Skip`
                if self.count == self.range.start {
                    self.count = self.range.end;
                    if let Some(Either::Iter(it)) = self.it.take() {
                        self.it = Some(Either::Skip(it.skip(self.range.end - self.range.start)));
                    }
                } else {
                    self.count += 1;
                }
                match &mut self.it {
                    Some(Either::Iter(it)) => it.next(),
                    Some(Either::Skip(it)) => it.next(),
                    _ => unreachable!(),
                }
            }
        }
    }
    
    use skip_range::SkipRange;
    
    fn main() {
        let v = vec![0, 1, 2, 3, 4, 5];
        let it = SkipRange::new(v.into_iter(), 2..4);
    
        let res: Vec<_> = it.collect();
        assert_eq!(res, vec![0, 1, 4, 5]);
    }
    

    原理是使用2个不同的迭代器:第一个是用户给定的,第二个是Skip迭代器,由第一个迭代器创建。

    【讨论】:

      【解决方案4】:

      如果您可以访问原始收藏,它可能是

      let items = ["a", "b", "c", "d"];
      let skipped_2nd = items.iter().take(1).chain(items.iter().skip(2));
      

      【讨论】:

        【解决方案5】:

        我不认为 stdlib 中有什么东西,但这里还有另一种非常简单的方法。

        fn main() {
            let (v, idx) = (vec!["foo", "bar", "baz", "qux"], 2_usize);
        
            let skipped = v[..idx].iter().chain(v[idx + 1..].iter());
            skipped.for_each(|&val| {
                dbg!(val);
            });
        }
        

        https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=f47a28fd681fee2fe82b57c073d52648

        【讨论】:

        • 只对vector有效,for_each()不生锈。
        • 我认为这并不完全正确,它应该适用于Index&lt;RangeTo&lt;usize&gt;&gt; + Index&lt;RangeFrom&lt;usize&gt;&gt; 的各种类型,对吧?例如,如果我将v 更改为[&amp;'static str; 4]&amp;[&amp;'static str; 4] 而不是Vec,它似乎工作正常。编辑:错字
        • 另外,我从未听过其他人抱怨for_each。这只是你的意见,还是在其他地方被正式贬低了?
        • vector 本质上是一个切片。对于您的最后一条消息,两者都是我的观点,并且它接受使用 for_each() 不是很好,因为迭代器不应该有副作用(或至少避免它)没有理由更喜欢 for_each() 当有 for清晰的生锈循环格式很好。
        • 正确。此外,Vec 是 OP 在他们的示例中使用的,并且由于所讨论的用例需要一个序列(应该保持顺序以使跳过有意义),我不明白你为什么对我使用它有异议我的答案。 doc.rust-lang.org/std/iter/trait.Iterator.html#method.for_each 专门引用 chain 作为 for_each 可能具有优势的情况,因此似乎有一些理由更喜欢它。对?编辑:错字