连接数组切片

时间:2016-06-02 07:54:09

标签: rust

我有两个(非常大)相同类型的数组foobar。为了能够编写一些不错的代码,我想获得两个数组串联的只读片result。此操作必须在O(1)时间和空间中运行。

result的数组访问权限也必须在O(1)中。更一般地说,如果resultk数组切片的串联,则result的任意数组访问应该在O(k)中运行。

我不想复制foobar的任何元素。

这似乎很容易实现到Rust核心,但没有多少搜索为我带来了解决方案。

3 个答案:

答案 0 :(得分:10)

没有预定义的类型,但您可以通过为包含两个切片的类型实现Index特征来轻松创建自己的类型:

use std::ops::Index;

struct Slice<'a, T: 'a>(&'a[T], &'a[T]);

impl<'a, T: 'a> Index<usize> for Slice<'a, T> {
    type Output = T;
    fn index(&self, index: usize) -> &T {
        if index < self.0.len() {
            &self.0[index]
        } else {
            &self.1[index - self.0.len()]
        }
    }
}
  

更一般地说,如果resultk数组切片的串联,则result的任意数组访问应该在O(k)中运行。

如果切片连接为O(log(k)),则可以在O(k)中获取切片访问权限,方法是创建一个包含切片累积长度的数组,并使用二进制搜索来查找要索引的实际切片成。

这需要一个宏,因为我们还没有足够好的常量评估器,也没有值泛型。

答案 1 :(得分:3)

对于n个数组,您可以使用Vec实现它,如下所示:

use std::ops::Index;

struct VecSlice<'a, T: 'a>(Vec<&'a [T]>);

impl<'a, T> Index<usize> for VecSlice<'a, T> {
    type Output = T;
    fn index(&self, mut index: usize) -> &T {
        for slice in self.0.iter() {
            if index < slice.len() {
                return &slice[index];
            } else {
                index -= slice.len();
            }
        }
        panic!("out of bound");
    }
}

然后像数组一样访问它,只是不要走出界限。

fn main() {
    let a1 = [0, 1, 2];
    let a2 = [7, 8, 9];
    let a = VecSlice(vec!(&a1, &a2));
    println!("{}", a[4]);
}

打印出来

8

答案 2 :(得分:2)

如果你要求结果是一个真正的切片,我担心你所要求的几乎是不可能的。切片是内存块的视图。连续的记忆。如果您想通过组合另外两个切片来创建新切片,则必须将内容复制到新位置,以便获得新的连续内存块。

如果您对通过复制concat进行连接感到满意,则会在切片上提供方法joinClone,只要它们实现{{1},就可以在自定义类型的切片上使用}}:

#[derive(Clone, PartialEq, Debug)]
struct A {
    a: u64,
}

fn main() {
    assert_eq!(["hello", "world"].concat(), "helloworld");
    assert_eq!([[1, 2], [3, 4]].concat(), [1, 2, 3, 4]);
    assert_eq!([[A { a: 1 }, A { a: 2 }], [A { a: 3 }, A { a: 4 }]].concat(),
               [A { a: 1 }, A { a: 2 }, A { a: 3 }, A { a: 4 }]);
}

请注意,即使SliceConcatExt不稳定,方法本身也是稳定的。因此,如果复制正常,没有理由不使用它们。如果你不能复制你不能得到一个切片。在这种情况下,您需要创建一个包装器类型,如the answer of ker中所述。