【问题标题】:Remove an element from a vector从向量中删除一个元素
【发布时间】:2014-10-07 18:45:30
【问题描述】:

有没有一种简单的方法可以从Vec<T> 中删除元素?

有一个名为remove() 的方法,它需要一个index: usize,但我什至看不到index_of() 方法。

我正在寻找一些(希望)简单且 O(n) 的东西。

【问题讨论】:

    标签: rust


    【解决方案1】:

    这是我迄今为止提出的(这也让借阅检查员很高兴):

    let index = xs.iter().position(|x| *x == some_x).unwrap();
    xs.remove(index);
    

    我仍在等待找到更好的方法来做到这一点,因为这很丑。

    注意:我的代码假定该元素确实存在(因此是 .unwrap())。

    【讨论】:

    • 请注意,stdlib 仍在设计中,因此可能缺少一些其他语言中常见的功能。随时提交 PR 添加此内容!
    • 在使用 rust 一段时间后,删除通常在索引列表中完成,因此索引上的过滤/保留实际上比从中间删除便宜得多
    • Rust 实际上曾经有一个功能可以做到这一点,但后来弃用了它doc.rust-lang.org/std/vec/struct.Vec.html#method.remove_item 所以我想他们根本不认为它是必要的
    【解决方案2】:

    您可以使用retain method,但它会删除该值的每个实例:

    fn main() {
        let mut xs = vec![1, 2, 3];
        let some_x = 2;
        xs.retain(|&x| x != some_x);
        println!("{:?}", xs); // prints [1, 3]
    }
    

    【讨论】:

    • 找到元素后的比较是不必要的
    • @malbarbo 是的,这是因为此方法会删除该值的每个实例。
    【解决方案3】:

    您的问题没有明确说明:您是要返回 所有 项等于您的针还是只返回 一个?如果有,第一个还是最后一个?如果没有一个元素等于你的针呢?可以用快速的swap_remove 删除它还是需要较慢的remove?为了迫使程序员思考这些问题,没有简单的方法可以“删除一个项目”(有关详细信息,请参阅this discussion)。

    删除 first 元素等于needle

    // Panic if no such element is found
    vec.remove(vec.iter().position(|x| *x == needle).expect("needle not found"));
    
    // Ignore if no such element is found
    if let Some(pos) = vec.iter().position(|x| *x == needle) {
        vec.remove(pos);
    }
    

    您当然可以随心所欲地处理None 案例(恐慌和忽略不是唯一的可能性)。

    删除 last 元素等于needle

    与第一个元素类似,但将 position 替换为 rposition

    删除所有元素等于needle

    vec.retain(|x| *x != needle);
    

    ... 或swap_remove

    请记住,remove 的运行时间为 O(n),因为索引之后的所有元素都需要移动。 Vec::swap_remove 的运行时间为 O(1),因为它将要删除的元素与最后一个元素交换。如果在您的情况下元素的顺序并不重要,请使用swap_remove 而不是remove

    【讨论】:

      【解决方案4】:

      迭代器有一个position() 方法,它返回与谓词匹配的第一个元素的索引。相关问题:Is there an equivalent of JavaScript's indexOf for Rust arrays?

      还有一个代码示例:

      fn main() {
          let mut vec = vec![1, 2, 3, 4];
      
          println!("Before: {:?}", vec);
      
          let removed = vec.iter()
              .position(|&n| n > 2)
              .map(|e| vec.remove(e))
              .is_some();
      
          println!("Did we remove anything? {}", removed);
      
          println!("After: {:?}", vec);
      }
      

      【讨论】:

      • 这不会编译:xs.remove(xs.iter().position(|x| *x == some_x).unwrap()); -- “不能将xs 借用为不可变的,因为它也被借用为可变的”
      • @Kai Sellgren:也称为:不要修改您正在迭代的容器。
      【解决方案5】:

      drain_filter() 是最新答案中的新成员吗?

      好像和凯的回答差不多:

      #![feature(drain_filter)]
      let mut numbers = vec![1, 2, 3, 4, 5, 6, 8, 9, 11, 13, 14, 15];
      
      numbers.drain_filter(|x| *x % 2 == 0).collect::<Vec<_>>();
      
      assert_eq!(numbers, vec![1, 3, 5, 9, 11, 13, 15]);
      

      https://doc.rust-lang.org/std/vec/struct.Vec.html#method.drain_filter

      【讨论】:

      • drain_filter:仍然只适用于夜间和实验性。
      【解决方案6】:

      如果您的数据已排序,请使用二进制搜索来删除O(log n),这对于大型输入可能会快得多。

      match values.binary_search(value) {
        Ok(removal_index) => values.remove(removal_index),
        Err(_) => {} // value not contained.
      }
      

      【讨论】:

      • 无论如何,删除操作都是 O(log n),所以这个解决方案不是 O(log n),即使它的搜索部分是。
      • 在99%的实际案例中,这种情况下你想要的数据结构是HashSet。然后搜索和删除是O(1)。
      • 他只是建议将顺序搜索部分更改为二进制搜索(如果全部设置),这是一个有效的问题。所以只是想帮忙,不值得-1。
      猜你喜欢
      • 1970-01-01
      • 2012-03-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-05-05
      相关资源
      最近更新 更多