簡體   English   中英

如何迭代一次向量,並在此過程中插入/刪除/修改多個元素?

[英]How can I iterate a vector once and insert/remove/modify multiple elements along the way?

我想迭代一次數組/向量,並在此途中修改多個元素,因為這是最佳的解決方案。 我不想一遍又一遍地掃描它,因為Rust對借貸不滿意。

我將以[start;stop]表示的間隔列表存儲在排序的向量中,我想添加一個新間隔。 它可能是重疊的,所以我想刪除不再需要的所有元素。 我想一勞永逸。 算法看起來像這樣(我削減了一些部分):

use std::cmp::{min, max};

#[derive(Debug, PartialEq, Clone, Copy)]
struct Interval {
    start: usize,
    stop: usize,
}

impl Interval {
    fn new(start: usize, stop: usize) -> Interval {
        Interval {
            start: start,
            stop: stop,
        }
    }
    pub fn starts_before_disjoint(&self, other: &Interval) -> bool {
        self.start < other.start && self.stop < other.start
    }
    pub fn starts_before_non_disjoint(&self, other: &Interval) -> bool {
        self.start <= other.start && self.stop >= other.start
    }
    pub fn starts_after(&self, other: &Interval) -> bool {
        self.start > other.start
    }
    pub fn starts_after_disjoint(&self, other: &Interval) -> bool {
        self.start > other.stop
    }
    pub fn starts_after_nondisjoint(&self, other: &Interval) -> bool {
        self.start > other.start && self.start <= other.stop
    }
    pub fn disjoint(&self, other: &Interval) -> bool {
        self.starts_before_disjoint(other)
    }
    pub fn adjacent(&self, other: &Interval) -> bool {
        self.start == other.stop + 1 || self.stop == other.start - 1
    }
    pub fn union(&self, other: &Interval) -> Interval {
        Interval::new(min(self.start, other.start), max(self.stop, other.stop))
    }
    pub fn intersection(&self, other: &Interval) -> Interval {
        Interval::new(max(self.start, other.start), min(self.stop, other.stop))
    }
}

fn main() {
    //making vectors
    let mut vec = vec![
        Interval::new(1, 1),
        Interval::new(2, 3),
        Interval::new(6, 7),
    ];
    let addition = Interval::new(2, 5); // <- this will take over interval @ 2 and will be adjacent to 3, so we have to merge
    let (mut i, len) = (0, vec.len());
    while i < len {
        let r = &mut vec[i];
        if *r == addition {
            return; //nothing to do, just a duplicate
        }
        if addition.adjacent(r) || !addition.disjoint(r) {
            //if they are next to each other or overlapping
            //lets merge
            let mut bigger = addition.union(r);
            *r = bigger;
            //now lets check what else we can merge
            while i < len - 1 {
                i += 1;
                let next = &vec[i + 1];
                if !bigger.adjacent(next) && bigger.disjoint(next) {
                    //nothing to merge
                    break;
                }
                vec.remove(i); //<- FAIL another mutable borrow
                i -= 1; //lets go back
                vec[i] = bigger.union(next); //<- FAIL and yet another borrow
            }
            return;
        }
        if addition.starts_before_disjoint(r) {
            vec.insert(i - 1, addition); // <- FAIL since another refence already borrowed @ let r = &mut vec[i]
        }
        i += 1;
    }
}

由於借款規則,它在幾個地方失敗了。 有沒有辦法

  1. 一口氣用迭代器完成
  2. 解決借款問題

借用拆分功能 ,但我看不到如何在這里應用。

通常,您不能這樣做,因為這正是Rust可以防止的一類錯誤 檢查此事件序列,在該序列中我已用唯一變量替換了i ,因為編譯器仍然不知道將使用什么值。

let r = &mut vec[i1];
let next = &vec[i2];
vec.remove(i3);
vec[i4] = bigger.union(next);         
vec.insert(i5, addition);
  • 如果在調用vec.remove(i3)時刪除了i1i2 之前的任何值,則nextr的引用將無效,因為所有值都將移動。
  • 如果i5i1i2之前,則將發生同樣的事情,只是方向相反。
  • 如果i4等於i2 ,那么next不變值將被更改。
  • 如果i4等於i1 ,則對r修改將通過可變引用的單個所有者以外的其他路徑進行。

請注意,這些參數如何與編譯器告訴您的要點相對應。

可能一些案件可能通過非詞匯的壽命是固定的,如果編譯器變得足夠聰明地理解您不再需要有圍繞基准。 在通過數組索引更改向量的情況下將無濟於事; 編譯器不夠聰明,無法跟蹤數學並證明您從未碰過“錯誤的”索引,如果索引是索引,則編譯器也不夠聰明,無法意識到數組中的兩個引用是不相交的。


這種特定情況下 ,由於您的類型實現了Copy ,請利用該類型獲取值。 必要時直接寫回向量。 如果您從不借款,就不會有借款錯誤。

fn main() {
    let mut vec = vec![
        Interval::new(1, 1),
        Interval::new(2, 3),
        Interval::new(6, 7),
    ];
    let addition = Interval::new(2, 5);
    let (mut i, len) = (0, vec.len());
    while i < len {
        let r = vec[i];
        if r == addition {
            return;
        }
        if addition.adjacent(&r) || !addition.disjoint(&r) {
            let mut bigger = addition.union(&r);
            vec[i] = bigger;
            while i < len - 1 {
                i += 1;
                let next = vec[i + 1];
                if !bigger.adjacent(&next) && bigger.disjoint(&next) {
                    break;
                }
                vec.remove(i); 
                i -= 1;
                vec[i] = bigger.union(&next);
            }
            return;
        }
        if addition.starts_before_disjoint(&r) {
            vec.insert(i - 1, addition);
        }
        i += 1;
    }
}

實際上,我會按照loganfsmyth的建議進行操作 ,並將算法更改為采用一片間隔並返回一個新的Vec 如果您經常這樣做,則可以在兩個預分配的Vec之間來回翻轉寫入,但是到那時,數據結構可能比矢量要好得多。 也許是一棵間隔樹

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM