Algorithm 如何迭代一次向量,并在此过程中插入/删除/修改多个元素?

Algorithm 如何迭代一次向量,并在此过程中插入/删除/修改多个元素?,algorithm,rust,Algorithm,Rust,我想迭代一次数组/向量,并在此过程中修改多个元素,因为这是最佳解决方案。我不想一次又一次地扫描它,仅仅因为Rust对借款不满意 我将表示为[start;stop]的间隔列表存储在排序向量中,并希望添加一个新的间隔。它可能是重叠的,所以我想删除所有不再需要的元素。我想一次完成这一切。算法可以如下所示(我切割了一些部分): 使用std::cmp::{min,max}; #[派生(调试、分区、克隆、复制)] 结构间隔{ 开始:使用, 停止:使用, } 脉冲间隔{ fn新建(开始:使用,停止:使用)->

我想迭代一次数组/向量,并在此过程中修改多个元素,因为这是最佳解决方案。我不想一次又一次地扫描它,仅仅因为Rust对借款不满意

我将表示为
[start;stop]
的间隔列表存储在排序向量中,并希望添加一个新的间隔。它可能是重叠的,所以我想删除所有不再需要的元素。我想一次完成这一切。算法可以如下所示(我切割了一些部分):

使用std::cmp::{min,max};
#[派生(调试、分区、克隆、复制)]
结构间隔{
开始:使用,
停止:使用,
}
脉冲间隔{
fn新建(开始:使用,停止:使用)->间隔{
间歇{
开始:开始,
停:停,,
}
}
pub fn在不相交(&self,other:&Interval)->bool之前启动{
self.startbool之前启动{
self.start=other.start
}
发布fn在(&self,other:&Interval)->bool之后启动{
self.start>other.start
}
pub fn在不相交(&self,other:&Interval)->bool之后启动{
self.start>other.stop
}
pub fn在非分离(&self,其他:&Interval)->bool之后启动{
self.start>other.start&&self.start bool{
self.在不相交(其他)之前启动
}
发布fn相邻(&self,其他:&Interval)->bool{
self.start==other.stop+1 | | self.stop==other.start-1
}
发布fn联合(&self,其他:&Interval)->Interval{
间隔::新建(最小值(自启动,其他.启动),最大值(自停止,其他.停止))
}
发布fn交叉口(&self,其他:&Interval)->Interval{
间隔::新建(最大值(自启动,其他.启动),最小值(自停止,其他.停止))
}
}
fn main(){
//制作向量
让mut-vec=vec[
间隔::新的(1,1),
间隔:新的(2,3),
间隔:新的(6,7),
];

让addition=Interval::new(2,5);//一般来说,你不能,因为这正是一类可以防止生锈的bug。检查一下我用唯一变量替换
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)
    时删除
    i1
    i2
    之前的任何值,则
    next
    r
    中的引用将无效,因为所有值都将移到上面
  • 如果
    i5
    i1
    i2
    之前,那么同样的事情也会发生,只是在另一个方向
  • 如果
    i4
    等于
    i2
    ,则将更改
    next
    不可变值
  • 如果
    i4
    等于
    i1
    ,则对
    r
    的修改将通过可变引用的单一所有者之外的另一条路径进行
注意每一个都与编译器告诉您的点相对应

如果编译器变得足够聪明,能够理解您不再需要引用,那么其中一些情况可能会通过非词汇生存期得到修复。这对通过数组索引更改向量的情况没有帮助;编译器不够聪明,无法跟踪您的数学并证明您从未使用过触摸“错误”索引,也不会聪明到意识到如果索引是不相交的,那么数组中的两个引用是不相交的


这种特定情况下,由于您的类型实现了
复制
,因此可以利用它来获取值。需要时直接写回向量。如果从不借用,则不会出现借用错误

fn main(){
让mut-vec=vec[
间隔::新的(1,1),
间隔:新的(2,3),
间隔:新的(6,7),
];
让加法=区间::新(2,5);
设(muti,len)=(0,vec.len());
而我{
设r=vec[i];
如果r==加法{
返回;
}
如果加法.相邻(&r)| |!加法.不相交(&r){
让mut biger=addition.union(&r);
vec[i]=更大;
而我

实际上,我会这样做,并更改算法,以获取一段间隔并返回一个新的
Vec
。如果您经常这样做,您可以在两个预先分配的
Vec
之间来回翻转写入,但在这一点上,可能有一个比向量好得多的数据结构;可能是一个变异
vec
是一个明确的目标吗?这似乎会非常容易实现,通过制作一个新的
vec
并向其中添加项目,而不是试图更改原始的
vec
@loganfsmyth。这可能是一个小向量、小数据结构的选项。很好的答案,谢谢!我想我会选择复制现在,考虑到区间结构的大小——这真的不是问题,我只是想知道如果区间的大小合适,我该怎么做structure@Windys如果
Interval
是一个相当大的结构,我应该做什么?如果必须使用原始代码,您可以始终使用
unsafe
来强制编译器允许您键入代码。然后由您来确保满足所有要求
let r = &mut vec[i1];
let next = &vec[i2];
vec.remove(i3);
vec[i4] = bigger.union(next);         
vec.insert(i5, addition);
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;
    }
}