【问题标题】:How do I efficiently iterate through a `Vec<Vec<T>>` row by row?如何有效地逐行迭代`Vec<Vec<T>>`?
【发布时间】:2019-02-18 22:14:30
【问题描述】:

我正在编写一个库,它采用Vec&lt;Vec&lt;T&gt;&gt; 类型以列优先顺序存储数据(每个内部Vec 代表一列)。用户可以创建具有任意行和列长度的Vec&lt;Vec&lt;T&gt;&gt;,但所有列都被限制为相同的长度。

有时我需要逐行有效地遍历Vec&lt;Vec&lt;T&gt;&gt;。我不想更改数组类型,因为大多数时候我需要“按列向量”迭代(一次一个完整的列向量)。

除非我遗漏了什么,否则Iterator::zip 不是一个选项,因为我事先不知道列向量的数量。 Itertools::izipItertools::multizip 也不可行。

这是我的示例代码:

let array = vec![vec![1, 2, 3], vec![4, 5, 6], vec![7, 8, 9]];
let mut iterators: Vec<_> = array.iter().map(|x| x.iter()).collect();
for _ in 0..array[0].len() {
    let values: Vec<_> = iterators.iter_mut().map(|x| x.next().unwrap()).collect();
    dbg!(values);
}

我应该在开始迭代之前定义一个可变的values 向量以避免在每个周期进行分配,还是编译器会处理这种优化?自己找到最简单的方法是什么?

是否有更有效/惯用的解决方案?

【问题讨论】:

标签: rust


【解决方案1】:

一旦我有了一个迭代器向量,如何将它转换为向量迭代器?

有两种创建迭代器的方法:使用现有的迭代器适配器或实现自定义迭代器。

让我们采用第二种方法并定义一个自定义迭代器类型,该类型采用迭代器向量:

struct DynamicZip<I>
where I: Iterator {
    iterators: Vec<I>
}

让我们提供一个迭代器实现:

impl<I, T> Iterator for DynamicZip<I>
where I: Iterator<Item = T> {
    type Item = Vec<T>;
    fn next(&mut self) -> Option<Self::Item> {
        let output: Option<Vec<T>> = self.iterators.iter_mut().map(|iter| iter.next()).collect()
        output
    }
}

我们完成了!

回到原来的例子

fn main() {
    let array = vec![vec![1, 2, 3], vec![4, 5, 6], vec![7, 8, 9]];
    let iterators: Vec<_> = array.into_iter().map(|v| v.into_iter()).collect();
    let dz = DynamicZip { iterators: iterators };
    // use the Iterator type we just defined
    for column in dz {
        println!("{:?}", column)
    }
}

将产生输出

[1, 4, 7]
[2, 5, 8]
[3, 6, 9]

【讨论】:

  • 那效率不高。
  • 澄清说,对于我的数据模型,在效率方面我无能为力,我将在我的代码中使用这个解决方案。恕我直言,dynamiczip 除了multizip 之外,还可以考虑添加到itertools 板条箱中。
【解决方案2】:

您的Vec&lt;Vec&lt;T&gt;&gt; 是一个面向列的矩阵,其中每个内部Vec 是一列,因此,只需执行@987654323 就可以在运行时知道列数@操作。

同时使用行和列,更容易创建Iterator。这是一个例子:

fn main() {
    let matrix = vec![vec![1, 2, 3], vec![4, 5, 6], vec![7, 8, 9]];

    let columns = matrix.len();
    let rows = matrix[0].len();
    // If you know the number of rows in advance. E.g.: In some constructor
    // let rows = 3;

    let iter = (0..rows).map(|row_idx| matrix.iter().flatten().skip(row_idx).step_by(columns));

    for (row_idx, row_values) in iter.enumerate() {
        for (column_idx, value) in row_values.enumerate() {
            println!("[{}, {}] = {}", row_idx, column_idx, value);
        }
    }
}

【讨论】:

    猜你喜欢
    • 2020-01-22
    • 1970-01-01
    • 1970-01-01
    • 2021-08-26
    • 2015-05-13
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多