вычисление сумм столбцов матричного вектора & lt; vector & lt; double & gt; & GT; с итераторами?

В предыдущем посте вектор столбца с строкой означает — с std :: накопить? Я спросил, возможно ли, используя функциональность STL, вычислить средние значения матрицы

vector< vector<double> > data ( rows, vector<double> ( columns ) );

Лучший ответ @benjaminlindley — это не только то, что я искал, но и красота. Я всегда надеялся, что вычислить средние значения столбцов будет так же просто, как и STL-эквивалент

vector<double> colmeans( data[0].size() );
for ( int i=0; i<data.size(); i++ )
for ( int j=0; j<data[i].size(); j++ )
colmeans[j] += data[i][j]/data.size();

где среднее значение не вычисляется внутри каждого vector<double>, но через один и тот же индекс во всех векторах:

colmeans[0]       == ( data[0][0] + data[1][0] + ... data[rows][0] ) / rows
colmeans[1]       == ( data[0][1] + data[1][1] + ... data[rows][1] ) / rows
colmeans[2]       == ( data[0][2] + data[1][2] + ... data[rows][2] ) / rows
...
colmeans[columns] == ( data[0]   [columns] +
data[1]   [columns] +
...
data[rows][columns] ) / rows

Оказывается, совсем другое — накапливать не хочет работать с векторами векторов. Возможно ли как-то использовать накопление с [] оператор? Я даже не могу придумать промежуточную форму (чтобы избавиться от for i или же for j цикл), который не кажется правильным.

Что-то с accumulate и [] оператор? Или же bind?

6

Решение

Вот то, что я придумал, используя for_each а также transform:

std::vector<std::vector<double>> data { {1,2,3}, {1,2,3}, {1,2,3} };

std::vector<double> colsums( data[0].size() ); // initialize the size
// to number of columns

std::for_each(data.begin(), data.end(),

[&](const std::vector<double>& row)
{
// Use transform overload that takes two input ranges.
// Note that colsums is the second input range as well as the output range.
// We take each element of the row and add it to the corresponding
// element of colsums vector:
std::transform(row.begin(), row.end(), colsums.begin(), colsums.begin(),
[](double d1, double d2) { return d1 + d2; });
});

std::cout << "Column means: ";
std::transform(
colsums.begin(), colsums.end(),
std::ostream_iterator<double>(std::cout, " "),
[&data](double d) { return d / data.size(); });

LWS Demo

6

Другие решения

Прежде всего позвольте мне заявить, что вам действительно не следует вкладывать std :: vectors.
Кроме того, я получил какое-то решение, которое, конечно, длиннее, чем ваш исходный код, но в конечном итоге может сэкономить:

#include <vector>
#include <boost/iterator/iterator_adaptor.hpp>
#include <boost/iterator/counting_iterator.hpp>

typedef std::vector<std::vector<double> > Data;

struct ColumnElement : boost::iterator_adaptor<ColumnElement,
Data::const_iterator,
const double> {
int col;

ColumnElement(int col, const Data::const_iterator &iter)
: iterator_adaptor(iter), col(col)
{}
const double& dereference()const { return (*base())[col]; }
};

struct Column {
int col;
const Data *data;

Column(int col, const Data *data) : col(col), data(data) {}
ColumnElement begin()const { return ColumnElement(col, data->begin()); }
ColumnElement end()const { return ColumnElement(col, data->end()); }
int size()const { return std::distance(begin(), end()); }
};

struct Columns : boost::iterator_adaptor<Columns, boost::counting_iterator<int>,
Column, boost::use_default, Column> {
const Data *data;

Columns(int col, const Data *data): iterator_adaptor(col), data(data) {}

Column dereference()const { return Column(*base(), data); }
};

Columns columnsBegin(const Data &data) { return Columns(0, &data); }
Columns columnsEnd(const Data &data) {
return Columns(data.empty() ? 0 : data.front().size(), &data);
}

Это может быть использовано вкратце:

double Mean(const Column &d) {
return std::accumulate(d.begin(), d.end(), 0.0) / d.size();
}

int main() {
Data data = {   {1, 2, 3},
{2, 2, 2},
{9, 8, 7}};
std::vector<double> colMeans(data[0].size());
std::transform(columnsBegin(data), columnsEnd(data),
colMeans.begin(), Mean);
std::copy(colMeans.begin(), colMeans.end(),
std::ostream_iterator<double>(std::cout, ","));
std::cout << "\n";
}

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

Идея заключалась в том, чтобы создать итератор для всех столбцов (называется Columns только для краткости) и итератор, который перебирает все элементы одного столбца (ColumnElementтакже сокращенно, лучше назвать ColumnElementIterator) а также Column это представляет диапазон всех элементов одного столбца.

2