简体   繁体   English

如何在 Rust 中的索引上过滤向量

[英]How can I filter a vector on an index in Rust

I have a Vec<f64> and I am trying to get say every 7th element of the vector till I run out of bounds, into another Vec<f64> .我有一个Vec<f64> ,我试图说出向量的每个第 7 个元素,直到我用完界限,进入另一个Vec<f64> I thought maybe I could create an index of the elements I want and then filter based on that.我想也许我可以创建一个我想要的元素的索引,然后根据它进行过滤。 But I can't seem to be able to do this directly or indirectly.但我似乎无法直接或间接地做到这一点。 What I tried我试过的

let x: Vec<f64> = (1..200)
.map(|x| (x as f64)/(200 as f64))
.collect();

let y: Vec<f64> = x
.enumerate()
.filter(|&(i, _)| i % 7 == 0 )
.map(|(_, e)| e)
.collect();

But this did not work with compile error enumerate method cannot be called on Vec<f64> due to unsatisfied trait bounds .但这不适用于编译错误enumerate method cannot be called on Vec<f64> due to unsatisfied trait bounds I also found a retain method but don't see a way to apply it on the index rather than the element.我还找到了一个保留方法,但没有看到将它应用于索引而不是元素的方法。 A robust search of SO surprisingly did not yield anything.对 SO 的强大搜索令人惊讶地没有产生任何结果。

Thanks for the comments, patching everything together into a more complete answer for the community.感谢您的评论,将所有内容拼凑在一起,为社区提供更完整的答案。 Let's say this is the Vec: let x: Vec<f64> = (1..10).map(|x| (x as f64)/(10 as f64)).collect();假设这是 Vec: let x: Vec<f64> = (1..10).map(|x| (x as f64)/(10 as f64)).collect();

To filter the vector based on index, first we create an iterator with into_iter, then enumerate it to get index, then apply the filter, and then a map to remove the index, finally collecting it to f64 vector.要根据索引过滤向量,首先我们用 into_iter 创建一个迭代器,然后枚举它以获取索引,然后应用过滤器,然后使用映射删除索引,最后将其收集到 f64 向量。

let y: Vec<f64> = x
.into_iter()
.enumerate()
.filter(|&(i, _)| i % 2 == 0 )
.map(|(_, e)| e)
.collect();

If the scope of y is shorter than that of x , and if you had large values in y (say string), it might be preferable to make y a vector of references rather than values.如果y的范围比x的范围短,并且如果您在y中有较大的值(例如字符串),则最好将y设为引用向量而不是值。

let y: Vec<&f64> = x
.iter()
.enumerate()
.filter(|&(i, _)| i % 2 == 0 )
.map(|(_, e)| e)
.collect();

The key difference here is using iter() instead of iter_into() .这里的主要区别是使用iter()而不是iter_into() This page in rust book explains it: rust book中的这一页解释了它:

The iter method produces an iterator over immutable references. iter 方法在不可变引用上生成一个迭代器。 If we want to create an iterator that takes ownership of v1 and returns owned values, we can call into_iter instead of iter .如果我们想创建一个获取 v1 所有权并返回拥有值的迭代器,我们可以调用into_iter而不是iter Similarly, if we want to iterate over mutable references, we can call iter_mut instead of iter .类似地,如果我们想迭代可变引用,我们可以调用iter_mut而不是iter

Now, for this specific question, applying a filter to the index is probably not needed.现在,对于这个特定问题,可能不需要对索引应用过滤器。 A simpler way, as noted by Chayim below is正如下面 Chayim 所指出的,一种更简单的方法是

let y: Vec<_> = x.into_iter().step_by(2).collect();

I also found a retain method but don't see a way to apply it on the index rather than the element.我还找到了一个保留方法,但没有看到将它应用于索引而不是元素的方法。

While Vec::retain does not give you any sort of index, it takes an FnMut and is documented to operate in-order:虽然Vec::retain没有为您提供任何类型的索引,但它需要一个FnMut并记录为按顺序操作:

This method operates in place, visiting each element exactly once in the original order , and preserves the order of the retained elements.该方法在原地操作,按原始顺序对每个元素只访问一次,并保留保留元素的顺序。

So you can just keep track of the index yourself:所以你可以自己跟踪索引:

let mut idx = 0;
x.retain(|_| {
    let v = idx;
    idx += 1;
    v % 2 == 0
});

Or here you can specialise with a simple toggle:或者在这里你可以通过一个简单的切换来专注于:

let mut keep = false;
x.retain(|_| {
    keep = !keep;
    keep
});

请注意,有一个专门的迭代器适配器step_by()

let y: Vec<_> = x.into_iter().step_by(7).collect();

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

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