代码之家  ›  专栏  ›  技术社区  ›  eisterman

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

  •  12
  • eisterman  · 技术社区  · 6 年前

    迭代器具有 skip 跳过第一个的方法 n 要素:

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

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

    5 回复  |  直到 6 年前
        1
  •  18
  •   E_net4 Tunn    6 年前

    这似乎是一个非常具体的操作。标准库或 itertools 大木箱

    尽管如此,它还是很容易实现。可以枚举索引中的每个元素并进行筛选:

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

    Playground

        2
  •  13
  •   user25064    6 年前

    我偏爱 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

        3
  •  2
  •   Boiethios    5 年前

    我已经想跳过一些范围了。我认为最好是创建迭代器:

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

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

        4
  •  1
  •   Petr Gladkikh    5 年前

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

    let items = ["a", "b", "c", "d"];
    let skipped_2nd = items.iter().take(1).chain(items.iter().skip(2));
    
        5
  •  0
  •   n8henrie    3 年前

    我认为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