如何跳过 Rust 迭代器中的第 N 个元素?
How can I skip the Nth element in a Rust iterator?
迭代器有一个 skip
方法可以跳过前 n
个元素:
let list = vec![1, 2, 3];
let iterator = list.iter();
let skip_iter = iterator.skip(2); //skip the first 2 elements
我找不到只跳过迭代器中第 n
个元素的方法。我需要自己实现一些东西还是有什么方法我还没有找到?
这似乎是一个非常具体的操作。在标准库或 itertools
crate 中没有适配器。
尽管如此,实施起来还是很容易的。可以枚举每个元素并过滤索引:
iter.enumerate().filter(|&(i, _)| i != n).map(|(_, v)| v)
我偏向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);
}
我已经想跳过一些范围了。我认为最好的方法是创建一个迭代器:
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
迭代器,从第一个迭代器创建。
如果您可以访问原始 collection,它可能是
let items = ["a", "b", "c", "d"];
let skipped_2nd = items.iter().take(1).chain(items.iter().skip(2));
我认为 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);
});
}
迭代器有一个 skip
方法可以跳过前 n
个元素:
let list = vec![1, 2, 3];
let iterator = list.iter();
let skip_iter = iterator.skip(2); //skip the first 2 elements
我找不到只跳过迭代器中第 n
个元素的方法。我需要自己实现一些东西还是有什么方法我还没有找到?
这似乎是一个非常具体的操作。在标准库或 itertools
crate 中没有适配器。
尽管如此,实施起来还是很容易的。可以枚举每个元素并过滤索引:
iter.enumerate().filter(|&(i, _)| i != n).map(|(_, v)| v)
我偏向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);
}
我已经想跳过一些范围了。我认为最好的方法是创建一个迭代器:
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
迭代器,从第一个迭代器创建。
如果您可以访问原始 collection,它可能是
let items = ["a", "b", "c", "d"];
let skipped_2nd = items.iter().take(1).chain(items.iter().skip(2));
我认为 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);
});
}