Как мне эффективно перебрать `Vec`строка за строкой? - PullRequest
0 голосов
/ 19 февраля 2019

Я пишу библиотеку, которая использует тип Vec<Vec<T>> для хранения данных в главном порядке столбцов (каждый внутренний Vec представляет столбец).Пользователь может создать Vec<Vec<T>> с любой длиной строки и столбца, но все столбцы должны иметь одинаковую длину.

Мне иногда нужно эффективно перебирать Vec<Vec<T>> по строке.Я не хотел бы менять тип массива, потому что большую часть времени мне нужно выполнять итерацию «по вектору столбца» (по одному полному вектору столбца за раз).

Если я что-то не упустил, Iterator::zip невариант, потому что я не знаю количество векторов столбцов заранее.Itertools::izip и Itertools::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 перед началом итераций, чтобы избежать выделения вкаждый цикл, или компилятор позаботится об этой оптимизации в любом случае?Какой самый простой способ найти его сам?

Существуют ли более эффективные / идиоматические решения?

Ответы [ 2 ]

0 голосов
/ 20 февраля 2019

Ваш Vec<Vec<T>> является ориентированной на столбцы матрицей, где каждый внутренний Vec является столбцом, поэтому можно узнать количество столбцов во время выполнения , просто выполнив array.len()операция.

С помощью строк и столбцов проще создать 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);
        }
    }
}
0 голосов
/ 20 февраля 2019

Как только у меня есть вектор итераторов, как я могу преобразовать его в итератор векторов?

Существует два способа создания итератора: использовать существующий адаптер итератора или реализовать собственный итератор.

Давайте возьмем второй подход и определим пользовательский тип Итератора, который принимает вектор итераторов:

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]
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...