求和矩阵中的向量,在 C++ 中逐个元素

sum up vectors in a matrix, element by element in c++

C++中有没有一种简单的方法可以将组成矩阵的向量逐个元素相加?我的意思是,如果我有矩阵 M[3][4],我想要 sum[3] 包含以下组件的向量:

sum[0]=M[0][0]+M[1][0]+M[2][0]
sum[1]=M[0][1]+M[1][1]+M[2][1]
sum[2]=M[0][2]+M[1][2]+M[2][2]

我发现两个向量存在 ,我想将其扩展到许多向量,特别是组成矩阵 std::vector<vector<type> > Mstd::vector<type>rows,不知道-先验 M 的维数.

Is there a simple method in C++ that allows to sum up the vectors componing a matrix element by element? I mean, if I have the matrix M[3][4], I want the sum[3] vector with this components:

sum[0]=M[0][0]+M[1][0]+M[2][0]
sum[1]=M[0][1]+M[1][1]+M[2][1]
sum[2]=M[0][2]+M[1][2]+M[2][2]

很遗憾,C++标准库中没有简单的方法来添加 容器的元素按列排列。

std::accumulate(),但自然地,它会将行元素加在一起,而不是列元素,但我们可以通过遍历每一列来解决这个问题矩阵内的索引,并将元素一一相加:

#include <iostream>
#include <numeric>
#include <cstddef>
#include <vector>

// The below function assumes that all columns of your matrix have the same length
template <typename T>
std::vector<T> m_col_add(std::vector<std::vector<T>> const& mat) {
    std::vector<T> res;
    const auto column_size = mat[0].size();
    for (size_t x = 0; x < column_size; ++x)
        res.push_back(std::accumulate(mat.begin(), mat.end(), T{}, [x](T const& a, std::vector<T> const& row) {
            return a + row[x];
        }));
    return res;
}

int main() {
    std::vector<std::vector<int>> mat {
        {1, 2, 3, 4},
        {5, 6, 7, 8},
        {9, 10, 11, 12}
    };
    auto res = m_col_add(mat);
    for (auto const& elem : res)
        std::cout << elem << " ";
}

输出:

15 18 21 24 

或者,如果您在编译时已经知道行和列的大小并且使用的是 C++17 或更高版本,则可以使用 fold expressions and std::index_sequence<>通过编译时扩展更快地添加元素:

#include <iostream>
#include <utility>
#include <cstddef>
#include <array>

template <size_t Column, typename T, size_t Rows, size_t Columns, size_t ...Sizes>
T m_col_add_impl2(std::index_sequence<Sizes...>, std::array<std::array<T, Columns>, Rows> const& mat) {
    return (mat[Sizes][Column] + ...);
}

template <typename T, size_t Rows, size_t Columns, size_t ...Sizes>
std::array<T, Columns> m_col_add_impl1(std::index_sequence<Sizes...>, std::array<std::array<T, Columns>, Rows> const& mat) {
    std::array<T, Columns> sum;
    ((sum[Sizes] = m_col_add_impl2<Sizes>(std::make_index_sequence<Rows>(), mat)), ...);
    return sum;
}

template <typename T, size_t Rows, size_t Columns>
std::array<T, Columns> m_col_add(std::array<std::array<T, Columns>, Rows> const& mat) {
    return m_col_add_impl1(std::make_index_sequence<Columns>(), mat);
}

int main() {
    std::array mat {
        std::array {1, 2, 3, 4},
        std::array {5, 6, 7, 8},
        std::array {9, 10, 11, 12}
    };
    auto res = m_col_add(mat);
    for (auto const& elem : res)
    std::cout << elem << " ";
}

输出:

15 18 21 24 

您可以为向量定义 operator+=,这样您就可以定义一个广义的 Sum 函数,该函数接收要求和的范围的开始和结束运算符,适用于具有任何值类型的迭代器+= 运算符类似于提供 += 运算符的原始类型或(可能嵌套的)类型向量:

template<typename T>
std::vector<T>& operator+=(std::vector<T>& lhs, std::vector<T> const& rhs)
{
    if (lhs.empty())
    {
        lhs = rhs; // first summand; 0 + x = x 
    }
    else
    {    
        for (size_t i = 0; i < lhs.size(); ++i)
        {
            lhs[i] += rhs.at(i); // component-wise add
        }
    }
    return lhs;
}

// sum up elements in a given range
template<typename IteratorType>
typename std::iterator_traits<IteratorType>::value_type Sum(IteratorType summandBegin, IteratorType summandEnd)
{
    typename std::iterator_traits<IteratorType>::value_type sum {}; // 0 or object created with default constructor depending on the type
    while (summandBegin != summandEnd)
    {
        sum += *summandBegin;
        ++summandBegin;
    }
    return sum;
}

// sums the first count elements of a vector
template<typename T>
T PartialSum(std::vector<T> const& vec, size_t count)
{
    assert(vec.size() >= count);
    return Sum(vec.begin(), vec.begin() + count);
}

// logic for displaying
template<typename T>
std::ostream& operator<<(std::ostream& s, std::vector<T> const& vec)
{
    s << '{';
    for (auto& val : vec)
    {
        s << val << ", ";
    }
    s << '}';
    return s;
}

int main(int argc, char *argv[]) {
    std::vector<std::vector<std::vector<int>>> matrix { {{1, 2},{ 3, 4},{ 5, 6}},{{7, 8},{ 9, 10},{11, 12}},{{13, 14},{ 15, 16},{ 17, 18}}};

    auto partialSum = PartialSum(matrix, 2);

    std::cout << matrix << '\n' << partialSum << '\n';

    std::cout << "\nSomething extra:\n";
    std::vector<std::vector<std::string>> m2 = {{"Hell" , "Wo"} , {"o ", "rld!"}, {"foo", "bar"}};
    auto message = PartialSum(m2, 2);
    for (auto& msg : message)
    {
        std::cout << msg;
    }
    std::cout << '\n';

    return 0;
}