【问题标题】:Remove elements of vector in a loop based on index根据索引在循环中删除向量的元素
【发布时间】:2021-10-28 03:08:38
【问题描述】:

假设我有一个向量,值从 1 到 10。我希望如果您发现 5 和 5 彼此相邻,则将它们与下一个元素一起删除。

输入

[1, 2, 3, 4, 5, 5, 6, 7, 8, 9, 10]

预期输出

[1, 2, 3, 4] 

这是我的尝试。我正在寻找要删除的索引,但借用规则让我陷入困境。

let mut element = vec![1, 2, 3, 4, 5, 5, 6, 7, 8, 9, 10];
for (index, val) in element.iter().enumerate() {
    if *val == 5 {
        if let Some(next_val) = element.get(index + 1) {
            if *next_val == 5 {
                //element.drain(index..);
            }
        }
    }
}

【问题讨论】:

  • 来自切片的窗口和来自迭代器的位置也可能有帮助;),这是解决方案playground

标签: vector rust borrow-checker


【解决方案1】:

Rust 使您免于 迭代器失效(其他语言中常见的错误来源)。当您尝试修改数据结构同时对其进行迭代时,通常会发生这种错误。调用element.drain(index..) 后,您无法继续移动到(现已删除的)下一个元素。因此,您需要在该点之后添加break 以避免内存不安全。

在这种情况下,只需添加break; 就足以使代码编译。但是,要获得更简洁、线性的解决方案,请充分利用标准库提供的迭代器和方法:

if let Some(index) = element.windows(2).position(|pair| pair[0] == pair[1]) {
    element.truncate(index);
}

windows(2) 在一个切片上给出了一个迭代长度为 2 的子切片的迭代器,position 调用返回该迭代器的第一个元素的索引,其中切片的两个元素相等。 (如果不存在这样的对,position 返回None。)

我发现position 闭包随着(当前不稳定的)array_windows 功能变得更加明显:

if let Some(index) = element.array_windows().position(|[x, y]| x == y) {
    element.truncate(index);
}

Playground

相关

【讨论】:

  • 稳定的替代阵列窗口:.windows(2).flat_map(TryInto::<[i32; 2]>::try_into).position(|[x, y]| x == y)playground
【解决方案2】:

你不能做你想做的事,因为你想在迭代向量时从向量中删除一些元素。这是一个很大的错误。请注意,从向量中删除任何元素都会使迭代器无效,因此您将访问意外位置,因此 rust 不允许 UBs 你可以使用类似下面的东西

    let mut elements = vec![1, 2, 3, 4, 5, 5, 6, 7, 8, 9, 10];
    let mut first_repeated_five_index_op = None;
    for index in 0..elements.len()-1{
        if elements[index] == 5 && elements[index + 1] == 5{
            first_repeated_five_index_op = Some(index);
            break;
        }
    }
    if let Some(first_repeated_five_index) = first_repeated_five_index_op{ 
          elements.truncate(first_repeated_five_index);
    }
    println!("{:?}", elements);

查看Demo

【讨论】:

  • Nitpick:从向量中删除元素不会导致重新分配。但是,您正确地指出,它仍然会使对向量(包括迭代器)的现有引用无效。
  • Shift everything down to fill in that spot.,删除不会改变vector的实际容量,会导致重新分配,除非你调用Vec::shrink_to_fit,否则不会改变
  • @ÖmerErden 谢谢你。我认为它看起来像 C++
猜你喜欢
  • 1970-01-01
  • 2012-01-15
  • 2012-01-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-03-04
相关资源
最近更新 更多