Я использую Vec
для хранения 2D (основной ряд) матрицы значений. Я хотел бы перебрать эту матрицу со скользящим 2D-подокном, чтобы применить фильтр (который, к сожалению, нельзя разделить).
Я видел в документации по срезу, что существует функция windows
, которая это то, что я хочу, но в двух измерениях.
Я думал о реализации этого как:
fn main() {
// 4 rows 3 columns
let dim: (usize, usize) = (4, 3);
// Place-holder matrix
#[rustfmt::skip]
let mat = vec![0, 1, 2,
3, 4, 5,
6, 7, 8,
9, 10, 11];
// 2D index to 1D index
let linearize = |r, c| r * dim.1 + c;
// The dimensions of my sub-window
let win_size: usize = 2;
// Calculate the bounds for which the top left corner of each window may exist
let bounds: (usize, usize) = (dim.0 - win_size + 1, dim.1 - win_size + 1);
// Convert window 1D index into a 2D index
let split = |i| (i / win_size, i % win_size);
// Iterate over all the top left corners
let window_2d = (0..bounds.0 * bounds.1).map(|i| {
// Get the 2D index of the top left corner
let (r, c) = (i / bounds.1, i % bounds.1);
// Borrow the matrix, so our closure may own the reference
let bmat = &mat;
// Return an iterator for this window
return (0..win_size * win_size).map(move |x| {
let (wr, wc) = split(x);
return bmat[linearize(wr + r, wc + c)];
});
});
// Print the windows out
window_2d.for_each(|it| {
print!("[ ");
it.for_each(|x| print!("{} ", x));
println!("]");
});
}
По сути, создание итератора для диапазона индексов, а затем сопоставление с оператором квадратной скобки матрица. Насколько я знаю, это будет иметь накладные расходы на проверку границ для каждой разыменования итератора.
Мне интересно, есть ли альтернатива, которая исключила бы проверки границ? Может быть, используя комбинацию chunks
, windows
и zip
, чтобы разделить матрицу на строки, каждая со скользящим окном, затем сжать строку windows и сгладить результат?
Спасибо!
Редактировать : Я не хочу просто перебирать 2D-массив, я хочу скользить 2D-окном по массиву, подобно тому, как работает функция std::slice::windows
.