简体   繁体   English

是否可以就地过滤矢量?

[英]is it possible to filter on a vector in-place?

I'd like to remove some elements from a Vec , but vec.iter().filter().collect() creates a new vector with borrowed items.我想从Vec中删除一些元素,但是vec.iter().filter().collect()会创建一个包含借用项目的新向量。

I'd like to mutate the original Vec without extra memory allocation (and keep memory of removed elements as an extra capacity of the vector).我想在没有额外 memory 分配的情况下改变原始Vec (并保留 memory 的已删除元素作为向量的额外容量)。

If you want to remove elements, you can use retain() , which removes elements from the vector if the closure returns false : 如果要删除元素,可以使用retain() ,如果闭包返回false则从向量中删除元素:

let mut vec = vec![1, 2, 3, 4];
vec.retain(|&x| x % 2 == 0);
assert_eq!(vec, [2, 4]);

If you want to modify the elements in place, you have to do that in a for x in vec.iter_mut() . 如果要修改元素,则必须for x in vec.iter_mut()中的for x in vec.iter_mut()

If you truly want to mutate the vector's elements while filtering it, you can use the nightly-only method Vec::drain_filter , an extremely flexible tool: 如果你真的想过滤它时改变矢量的元素,你可以使用仅限夜间的方法Vec::drain_filter ,这是一个非常灵活的工具:

#![feature(drain_filter)]

fn main() {
    let mut vec = vec![1, 2, 3, 4];
    vec.drain_filter(|x| {
        if *x % 2 == 0 {
            true
        } else {
            *x += 100;
            false
        }
    });
    assert_eq!(vec, [101, 103]);
}

It also allows you to get the removed elements as the return value of the entire method is an iterator! 它还允许您获取已删除的元素,因为整个方法的返回值是迭代器!

Till Vec::drain_filter gets stable, we can solve the problem with homebrewed rust:直到Vec::drain_filter稳定下来,我们可以用 homebrewed rust 解决这个问题:

fn main() {
    let mut v = vec![1, 2, 3, 4];
    let mut i = 0;
    while i < v.len() {
        if v[i] % 2 == 0 {
            v.remove(i);
        } else {
            v[i] += 100;
            i += 1;
        }
    }
    println!("{:?}", v);  // [101, 103]
}

BTW remove() is an O(n) operation but doesn't allocate memory.顺便说一句, remove()是一个O(n)操作,但不分配 memory。
Playground 操场

I am providing my take for this problem as I was unaware of the retain method:我提供了我对这个问题的看法,因为我不知道保留方法:

impl<T> RemoveFilter<T> for Vec<T> {}
pub trait RemoveFilter<T>: BorrowMut<Vec<T>> {
    fn remove_filter<F: for<'b> FnMut(&'b T) -> bool>(&mut self, mut cb: F) {
        let vec: &mut Vec<T> = self.borrow_mut();
        let mut write_to = 0;
        let mut read_from = 0;
        while read_from < vec.len() {
            let maintain = cb(&mut vec[read_from]);
            if maintain {
                vec.as_mut_slice().swap(read_from, write_to);
                write_to += 1;
            }
            read_from += 1;
        }
        vec.resize_with(write_to, || panic!("We are shrinking the vector"));
    }
}

It will shift the elements as it iterates and then remove anything that is left behind.它会在迭代时移动元素,然后删除任何遗留的元素。 I think this is code may easily modified to solve other problems.我认为这是代码,可以很容易地修改以解决其他问题。

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

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