Сворачивание строк матрицы поэлементно и вычисление среднего значения в Rust

Предположим, у меня есть следующая матрица, представленная Vec<Vec<_>>:

[[5, 9, 4],
 [8, 8, 2],
 [4, 5, 3]]

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

[5.66, 7.33, 3] == [(5 + 8 + 4) / 3, (9 + 8 + 5) / 3, (4 + 2 + 3) / 3]

Каков самый идиоматический способ сделать это в Rust? Желательно без использования ndarray ящика.

Ты прав! Извини за это. Исправлено описание и добавлены случайные значения для устранения двусмысленности.

nobody 26.12.2020 19:23
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
1
357
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Учитывая, что внутренний Vec является столбцом, вы можете сложить() и суммировать().

fn col_means(mat: &[Vec<f64>]) -> Vec<f64> {
    assert!(!mat.is_empty());

    let col_len = mat[0].len();
    let mut col_means = mat.iter().fold(vec![0.0; col_len], |mut col_means, row| {
        row.iter()
            .enumerate()
            .for_each(|(i, cell)| col_means[i] += cell);
        col_means
    });
    for col in col_means.iter_mut() {
        *col /= col_len as f64;
    }

    col_means
}

fn main() {
    let mat: Vec<Vec<f64>> = vec![
        vec![5.0, 9.0, 4.0],
        vec![8.0, 8.0, 2.0],
        vec![4.0, 5.0, 3.0],
    ];

    let col_means = col_means(&mat);
    println!("{:?}", col_means);
    // Outputs `[5.666666666666667, 7.333333333333333, 3.0]`
}

В качестве альтернативы вы можете избежать внутреннего Vec и затем использовать chunks(), таким образом удаляя слой косвенности.

fn col_means(mat: &[f64], col_len: usize) -> Vec<f64> {
    let mut col_means = mat
        .chunks(col_len)
        .fold(vec![0.0; col_len], |mut col_means, row| {
            row.iter()
                .enumerate()
                .for_each(|(i, cell)| col_means[i] += cell);
            col_means
        });
    for col in col_means.iter_mut() {
        *col /= col_len as f64;
    }

    col_means
}

fn main() {
    let mat: Vec<f64> = vec![5.0, 9.0, 4.0,
                             8.0, 8.0, 2.0,
                             4.0, 5.0, 3.0];

    let col_means = col_means(&mat, 3);
    println!("{:?}", col_means);
    // Outputs `[5.666666666666667, 7.333333333333333, 3.0]`
}

Старый ответ

Предполагая, что внутренний Vec является строкой. Затем вы можете использовать комбинацию iter() , sum() , а затем collect() в Vec.

let mat: Vec<Vec<i32>> = vec![vec![1, 2, 3], vec![2, 3, 4], vec![3, 4, 5]];

let row_means = mat
    .iter()
    .map(|row| row.iter().sum::<i32>() / (row.len() as i32))
    .collect::<Vec<_>>();

println!("{:?}", row_means);
// Outputs `[2, 3, 4]`

В качестве альтернативы вы можете избежать внутреннего Vec и затем использовать chunks(), таким образом удаляя слой косвенности.

let mat: Vec<i32> = vec![1, 2, 3, 2, 3, 4, 3, 4, 5];
let row_len = 3;

let row_means = mat
    .chunks(row_len as usize)
    .map(|row| row.iter().sum::<i32>() / row_len)
    .collect::<Vec<_>>();

println!("{:?}", row_means);
// Outputs `[2, 3, 4]`

Затем вы можете абстрагироваться и спрятать реализацию в многоразовый struct Mat.

struct Mat(usize, Vec<i32>);

impl Mat {
    fn row_means(&self) -> Vec<i32> {
        let row_len = self.row_len();
        self.1
            .chunks(row_len)
            .map(|row| row.iter().sum::<i32>() / (row_len as i32))
            .collect()
    }

    fn cell(&self, row: usize, col: usize) -> i32 {
        self.1[col + row * self.row_len()]
    }

    fn row_len(&self) -> usize {
        self.0
    }

    fn col_len(&self) -> usize {
        self.1.len() / self.row_len()
    }
}

fn main() {
    let mat = Mat(3, vec![1, 2, 3,
                          2, 3, 4,
                          3, 4, 5]);
    println!("{:?}", mat.row_means());
    // Outputs `[2, 3, 4]`
}

И правда перепутал первый. Я исправил это сейчас. Обычно я считаю x_{count,size,len} синонимами, но да, в данном случае я вижу, что row_count звучит неправильно. Я переименовал его в row_len, чтобы он больше соответствовал Rust, чем row_size :)

vallentin 26.12.2020 19:17

Я написал функцию для вычисления среднего столбца сеток произвольного размера:

#[derive(Debug)]
struct EmptyGrid;

fn mean_column(grid: &[Vec<f64>]) -> Result<Vec<f64>, EmptyGrid> {
    if grid.is_empty() {
        return Err(EmptyGrid);
    }
    if grid[0].is_empty() {
        return Ok(Vec::new());
    }
    let mut mean = grid[0].to_vec();
    let col_len = mean.len();
    for row in grid.iter().skip(1) {
        for i in 0..col_len {
            mean[i] += row[i];
        }
    }
    let row_len = grid.len() as f64;
    for sum in mean.iter_mut() {
        *sum /= row_len;
    }
    Ok(mean)
}

fn main() {
    let grid = vec![
        vec![5.0, 9.0, 4.0],
        vec![8.0, 8.0, 2.0],
        vec![4.0, 5.0, 3.0],
    ];
    let mean_column = mean_column(&grid).unwrap();
    dbg!(mean_column); // prints [5.66, 7.33, 3.0]
}

детская площадка

Другие вопросы по теме