First let me state that you really should not nest std::vectors.
Apart from that I got some solution which is of course longer than your initial code but that could save in the long run:
#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);
}
This could be used in short:
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";
}
I employed some boost functionality to shorten it, but it could be done without boost (however much longer).
The idea was to create an iterator over all columns (called Columns
just for shortness) and an iterator that iterates over all elements of one column (ColumnElement
, also shortened, should be better named ColumnElementIterator
) and Column
that represents the range of all Elements of one column.