问题
I have a Boost ublas matrix, and I want to print its contents to a text file. I have the following implementation, and it works.
#include <iostream>
using namespace std;
#include "boost\numeric\ublas\matrix.hpp"
typedef boost::numeric::ublas::matrix<float> matrix;
#include <algorithm>
#include <iterator>
#include <fstream>
int main()
{
fill(m1.begin2(), m1.begin2() + 400 * 500, 3.3);
ofstream dat("file.txt");
for (auto i = 0; i < 400 ; i++) {
for (auto j = 0; j < 500; j++) {
dat << m1(i, j) << "\t"; // Must seperate with Tab
}
dat << endl; // Must write on New line
}
I want to write this code without using the nested for loops. I tried the ostreambuf_iterator API as follows
copy(m1.begin2(), m1.begin2() + 500 * 400, ostream_iterator<float>(dat, "\n")); // Can only new line everything
However, as you can see, successive elements were written on new line, and I was not able to achieve the type of sequencing as I did with nested for loop. Is there a way to do what I did inside the nested for using an STL algorithm?
回答1:
I like Boost Spirit Karma for these kind of small formatting/generator tasks.
Direct approach
If you don't mind trailing tabs on each line, here's
Live On Coliru
matrix m1(4, 5);
std::fill(m1.data().begin(), m1.data().end(), 1);
using namespace boost::spirit::karma;
std::ofstream("file.txt") << format_delimited(columns(m1.size2()) [auto_], '\t', m1.data()) << "\n";
Prints
1.0 → 1.0 → 1.0 → 1.0 → 1.0 →
1.0 → 1.0 → 1.0 → 1.0 → 1.0 →
1.0 → 1.0 → 1.0 → 1.0 → 1.0 →
1.0 → 1.0 → 1.0 → 1.0 → 1.0 →
Using multi_array
view
You get much more flexibility when you use the const_multi_array_ref
adapter as a "view" on your raw storage:
Live On Coliru
std::ofstream("file.txt") << format(auto_ % '\t' % eol,
boost::const_multi_array_ref<float, 2>(&*m1.data().begin(), boost::extents[4][5]));
This results in the same, but doesn't have the trailing tabs on each line:
1.0 → 1.0 → 1.0 → 1.0 → 1.0
1.0 → 1.0 → 1.0 → 1.0 → 1.0
1.0 → 1.0 → 1.0 → 1.0 → 1.0
1.0 → 1.0 → 1.0 → 1.0 → 1.0
Update Make it more readable and less error prone with a helper function:
template <typename T> boost::const_multi_array_ref<T, 2> make_view(boost::numeric::ublas::matrix<T> const& m) {
return boost::const_multi_array_ref<T,2> (
&*m.data().begin(),
boost::extents[m.size1()][m.size2()]
);
}
So it becomes just
Live On Coliru
std::cout << format(auto_ % '\t' % eol, make_view(m1)) << "\n";
Which is very elegant, in my opinion
Note Of course these assume row-major layout.
来源:https://stackoverflow.com/questions/29308432/writing-a-boost-ublas-matrix-to-a-text-file