![](/img/trans.png)
[英]How to insert multiple elements in the vector at different positions using iterator?
[英]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;
}
}
由于借款规则,它在几个地方失败了。 有没有办法
有借用拆分功能 ,但我看不到如何在这里应用。
通常,您不能这样做,因为这正是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)
时删除了i1
或i2
之前的任何值,则next
和r
的引用将无效,因为所有值都将移动。 i5
在i1
或i2
之前,则将发生同样的事情,只是方向相反。 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.