首页 > 解决方案 > 在 Rust 中就地删除连续的重复元素

问题描述

我有以下python函数,可以就地删除连续重复的数字(意思是[0, 0, 1, 1, 1, 2, 2, 3]变成[0, 1, 2, 3]):

def del_consec_dupl(nums: List[int]):
    for (idx, n) in enumerate(nums):
        while idx < len(nums) - 1 and n == nums[idx + 1]:
            del nums[idx]

它需要用 Rust 重写,同时尊重它必须就地工作而不分配额外向量/数组的约束。当试图从字面上翻译这个时:

fn del_consec_dupl(nums: &mut Vec<i32>) {
    for (idx, n) in nums.iter().enumerate() {
        while idx < nums.len() - 1 && *n == nums[idx + 1] {
            nums.remove(idx);
        }
    }
}

将产生以下错误:

error[E0502]: cannot borrow `*nums` as immutable because it is also borrowed as mutable
 --> src/main.rs:4:21
  |
3 |     for (idx, n) in nums.iter_mut().enumerate() {
  |                     ---------------------------
  |                     |
  |                     mutable borrow occurs here
  |                     mutable borrow later used here
4 |         while idx < nums.len() - 1 && *n == nums[idx + 1] {
  |                     ^^^^ immutable borrow occurs here

error[E0502]: cannot borrow `*nums` as immutable because it is also borrowed as mutable
 --> src/main.rs:4:45
  |
3 |     for (idx, n) in nums.iter_mut().enumerate() {
  |                     ---------------------------
  |                     |
  |                     mutable borrow occurs here
  |                     mutable borrow later used here
4 |         while idx < nums.len() - 1 && *n == nums[idx + 1] {
  |                                             ^^^^ immutable borrow occurs here

error[E0499]: cannot borrow `*nums` as mutable more than once at a time
 --> src/main.rs:5:13
  |
3 |     for (idx, n) in nums.iter_mut().enumerate() {
  |                     ---------------------------
  |                     |
  |                     first mutable borrow occurs here
  |                     first borrow later used here
4 |         while idx < nums.len() - 1 && *n == nums[idx + 1] {
5 |             nums.remove(idx);
  |             ^^^^ second mutable borrow occurs here

error: aborting due to 3 previous errors

似乎无论我做什么,我只能解决 3 个中的 2 个。似乎这里的主要问题是试图在迭代内部发生变异时尝试引用向量的长度。

我需要一个unsafe街区吗?或者你将如何解决它?

标签: vectorrust

解决方案


我不会使用removewhich 在给定索引之后移动所有元素并且效率低下,而只是覆盖同一数组中的元素,通过使用索引来处理双借问题:

fn del_consec_dupl(nums: &mut Vec<i32>) {
    let mut di = 0; // "destination" increment
    for si in 1..nums.len() { // increment on the "source"
        if nums[si] != nums[si-1] {
            di += 1;
            nums[di] = nums[si];
        }
    }
    nums.truncate(di+1); // cut off the tail
}

没有必要在unsafe这里使用。


推荐阅读