有效地插入或在中间或A VEC的开始取代多个元素?有效地插入或在中间或A VEC的开始取代多个元素?

2019-05-12 04:40发布

有插入或从替换多个元件的任何直接的方式&[T]和/或Vec<T>在中间或者在开始时Vec线性时间?

我只能找到std::vec::Vec::insert ,但这只是用于插入单个元素O(n)时间,所以我显然不能称之为一个循环。

可以做一个split_off该索引, extend新的元素到分裂的左半边,然后extend下半年进入第一,但有没有更好的办法?

Answer 1:

铁锈1.21.0的, Vec::splice可用,并允许将在任何时候,包括完全前面加上:

let mut vec = vec![1, 5];
let slice = &[2, 3, 4];

vec.splice(1..1, slice.iter().cloned());

println!("{:?}", vec); // [1, 2, 3, 4, 5]

该文档的状态:

注4:这是最佳的,如果:

  • 尾部(在范围后的矢量元素)是空
  • replace_with产生比范围的长度更少的元件
  • 或下界其size_hint()是精确的。

在这种情况下,下界片的迭代器应该是准确的,所以应该执行一个存储的举动。


splice是因为它可以让你删除一个范围值(第一个参数),插入新的值(第二个参数),并根据需要获取旧值(调用的结果)更强大一点。

更换一组项目

let mut vec = vec![0, 1, 5];
let slice = &[2, 3, 4];

vec.splice(..2, slice.iter().cloned());

println!("{:?}", vec); // [2, 3, 4, 5]

获取以前的值

let mut vec = vec![0, 1, 2, 3, 4];
let slice = &[9, 8, 7];

let old: Vec<_> = vec.splice(3.., slice.iter().cloned()).collect();

println!("{:?}", vec); // [0, 1, 2, 9, 8, 7]
println!("{:?}", old); // [3, 4]


Answer 2:

好,存在VEC接口没有合适的方法(如我可以看到)。 但是,我们可以始终贯彻同样的事情自己。

的memmove

T复制 ,可能是最显而易见的方法是移动存储,就像这样:

fn push_all_at<T>(v: &mut Vec<T>, offset: usize, s: &[T]) where T: Copy {
    match (v.len(), s.len()) {
        (_, 0) => (),
        (current_len, _) => {
            v.reserve_exact(s.len());
            unsafe {
                v.set_len(current_len + s.len());
                let to_move = current_len - offset;
                let src = v.as_mut_ptr().offset(offset as isize);
                if to_move > 0 {
                    let dst = src.offset(s.len() as isize);
                    std::ptr::copy_memory(dst, src, to_move);
                }
                std::ptr::copy_nonoverlapping_memory(src, s.as_ptr(), s.len());
            }
        },
    }
}

拖曳

如果T是不可复制的,但它实现了克隆 ,我们可以追加定切片的VEC结束,并以线性时间使用交换的IT移动到所需的位置:

fn push_all_at<T>(v: &mut Vec<T>, mut offset: usize, s: &[T]) where T: Clone + Default {
    match (v.len(), s.len()) {
        (_, 0) => (),
        (0, _) => { v.push_all(s); },
        (_, _) => {
            assert!(offset <= v.len());
            let pad = s.len() - ((v.len() - offset) % s.len());
            v.extend(repeat(Default::default()).take(pad));
            v.push_all(s);
            let total = v.len();
            while total - offset >= s.len() {
                for i in 0 .. s.len() { v.swap(offset + i, total - s.len() + i); }
                offset += s.len();
            }
            v.truncate(total - pad);
        },
    }
}

迭代器CONCAT

也许是最好的选择将是在所有不修改VEC。 例如,如果你要通过迭代器访问的结果,我们就可以建立迭代器链从我们的块:

let v: &[usize] = &[0, 1, 2];
let s: &[usize] = &[3, 4, 5, 6];
let offset = 2;
let chain = v.iter().take(offset).chain(s.iter()).chain(v.iter().skip(offset));

let result: Vec<_> = chain.collect();
println!("Result: {:?}", result);


文章来源: Efficiently insert or replace multiple elements in the middle or at the beginning of a Vec?
标签: rust