简体   繁体   English

如何跳过 Rust 迭代器中的第 N 个元素?

[英]How can I skip the Nth element in a Rust iterator?

Iterators have a skip method that skips the first n elements:迭代器有一个跳过前n元素的skip方法:

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

I could not find a method to skip only the n -th element in the iterator.我找不到只跳过迭代器中第n个元素的方法。 Do I need to implement something on my own or is there a method somewhere I haven't found?我是否需要自己实现一些东西,或者是否有我没有找到的方法?

That seems to be a very specific operation.这似乎是一个非常具体的操作。 There is no adaptor for that in the standard library or the itertools crate.在标准库或itertools crate 中没有适配器。

It's easy to implement nonetheless.尽管如此,它还是很容易实现的。 One could enumerate each element and filter on the index:可以枚举每个元素并过滤索引:

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

Playground 操场

I am partial to the filter_map version我偏爱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 操场

I already wanted to skip some range.我已经想跳过一些范围。 The best in my opinion is to create an iterator:我认为最好的方法是创建一个迭代器:

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]);
}

The principle is to use 2 different iterators: the first one is given by the user, the second one is a Skip iterator, created from the first one.原则是使用 2 个不同的迭代器:第一个由用户提供,第二个是Skip迭代器,从第一个迭代器创建。

If you have access to original collection, it could be如果您可以访问原始集合,则可能是

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

I don't think there is something in the stdlib, but here's yet another pretty simple way to go about it.我认为 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 https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=f47a28fd681fee2fe82b57c073d52648

More concise:更简洁:

let iter = vs
            .iter()
            .enumerate()
            .filter_map(|(i, el)| (i == n).then(|| el));

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM