2

如果我有,Vec我可以使用索引通过 迭代元素v.iter().enumerate(),我可以通过删除元素v.retain()。有没有办法同时做到这两点?

在这种情况下,索引不能再用于访问元素——它将是循环开始之前元素的索引。

我可以自己实现它,但要尽可能高效.retain()地使用unsafe,我想避免这种情况。

这是我想要的结果:

let mut v: Vec<i32> = vec![1, 2, 3, 4, 5, 4, 7, 8];

v.iter()
    .retain_with_index(|(index, item)| (index % 2 == 0) || item == 4);

assert(v == vec![1, 3, 4, 5, 4, 7]);
4

3 回答 3

1

@Timmmm@Hauleth的回答非常务实,我想提供几个替代方案。

这是一个带有一些基准和测试的游乐场: https ://play.rust-lang.org/?version=nightly&mode=debug&edition=2018&gist=cffc3c39c4b33d981a1a034f3a092e7b

这很难看,但如果你真的想要一个方法,你可以用一个新的特性v.retain_with_index()对方法做一些复制粘贴:retain

trait IndexedRetain<T> {
    fn retain_with_index<F>(&mut self, f: F)
    where
        F: FnMut(usize, &T) -> bool;
}

impl<T> IndexedRetain<T> for Vec<T> {
    fn retain_with_index<F>(&mut self, mut f: F)
    where
        F: FnMut(usize, &T) -> bool, // the signature of the callback changes
    {
        let len = self.len();
        let mut del = 0;
        {
            let v = &mut **self;

            for i in 0..len {
                // only implementation change here
                if !f(i, &v[i]) {
                    del += 1;
                } else if del > 0 {
                    v.swap(i - del, i);
                }
            }
        }
        if del > 0 {
            self.truncate(len - del);
        }
    }
}

这样该示例将如下所示:

v.retain_with_index(|index, item| (index % 2 == 0) || item == 4);

或者...更好的是,您可以使用高阶函数:

fn with_index<T, F>(mut f: F) -> impl FnMut(&T) -> bool
where
    F: FnMut(usize, &T) -> bool,
{
    let mut i = 0;
    move |item| (f(i, item), i += 1).0
}

这样示例现在看起来像这样:

v.retain(with_index(|index, item| (index % 2 == 0) || item == 4));

(我的偏好是后者)

于 2020-01-06T18:49:23.840 回答
1

在 Rust 用户论坛上发现了基本相同的问题。他们提出了这个解决方案,这还不错:

let mut index = 0;
v.retain(|item| {
    index += 1;
    ((index - 1) % 2 == 0) || item == 4
});

当时它不是一个有效的解决方案,因为retain()不能保证迭代顺序,但我很高兴该线程中的某个人记录了这个顺序,所以现在它是。:-)

于 2020-01-05T18:10:30.397 回答
0

如果您想枚举、过滤(保留),然后收集结果向量,那么我会说要做到这一点:

v.iter()
    .enumerate()
    .filter(|&(idx, &val)| val - idx > 0)
    .collect()
于 2020-01-05T17:19:34.963 回答