首先,对不起,我不太了解很多c ++,也许我的问题有点愚蠢。 我有一个多维向量M.我希望能够沿着行i的元素或沿着列j的元素应用相同的函数。我不想两次写相同的功能。它可能以一种相当简单的方式执行此操作,例如一些重载或虚拟迭代器?谁能写一个简单的例子?谢谢。
答案 0 :(得分:1)
解决这个问题的一个好方法是使用std::transform
。有关详细信息,请参阅此link。以下是关于如何对行执行此操作的简短示例。专栏部分有点棘手。
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
const int nRowCnt = 3, nColCnt = 3;
int RowFunc(int i) { return ++i; }
int ColFunc(int i) { return --i; }
void PrintArray(vector<vector<int>>& vecArray, int nRowCnt, int nColCnt)
{
for (int nOuter = 0; nOuter < nRowCnt; nOuter++)
{
for (int nInner = 0; nInner < nColCnt; nInner++)
{
cout<<vecArray[nOuter][nInner]<<" ";
}
cout<<endl;
}
}
int main()
{
vector< vector<int> > vecVals(nRowCnt, vector<int>(nColCnt,0));
vector< int > rowOut(nColCnt*nRowCnt,0), colOut(nColCnt*nRowCnt,0);
vector<int>::iterator itrOut;
for (int nRow = 0; nRow < nRowCnt; nRow++)
{
for (int nCol = 0; nCol < nColCnt; nCol++)
{
vecVals[nRow][nCol] = nRow * (10+nCol) ;
}
}
PrintArray(vecVals,nRowCnt,nColCnt);
itrOut = rowOut.begin();
for (int nOuter = 0; nOuter < nRowCnt; nOuter++)
{
std::transform(vecVals[nOuter].begin(),vecVals[nOuter].end(),itrOut,RowFunc);
itrOut += nColCnt;
}
itrOut = colOut.begin();
for (int nOuter = 0; nOuter < nRowCnt; nOuter++)
{
for (int nInner = 0; nInner < nColCnt; nInner++)
{
std::transform( vecVals[nInner].begin() + nOuter, vecVals[nInner].begin() + nOuter +1, itrOut,ColFunc);
itrOut++;
}
}
cout<<endl<<"Row Transformed"<<endl;
for (itrOut = rowOut.begin(); itrOut != rowOut.end(); itrOut++)
cout<<*itrOut<<" ";
cout<<endl<<"Col Transformed"<<endl;
for (itrOut = colOut.begin(); itrOut != colOut.end(); itrOut++)
cout<<*itrOut<<" ";
cout<<endl;
return 0;
}
虽然有一个问题,列部分不适用于非方形2D数组(即它的工作行和列计数必须相同)。我想这可以解决一下。
答案 1 :(得分:1)
您可以在列上定义自己的迭代器,以便您可以使用标准算法(如另一个答案中提到的for_each
或transform
)将函数应用于行或列你只需要改变迭代器就可以了:
#include <iostream>
#include <iterator>
#include <vector>
#include <algorithm>
// Custom iterator to iterate over columns
// to be adapted to the underlying storage
class ColIterator : public std::iterator<std::forward_iterator_tag, double>
{
public:
typedef std::vector<std::vector<double> > MDarray;
ColIterator(MDarray & array, int i, int j) : array_(array), i_(i), j_(j) {}
ColIterator(const ColIterator& it) : array_(it.array_), i_(it.i_), j_(it.j_) {}
ColIterator& operator++() {
++i_;
return *this;
}
ColIterator operator++(int) {
ColIterator tmp(*this);
operator++();
return tmp;
}
bool operator==(const ColIterator& rhs) { return &array_==&rhs.array_ && i_==rhs.i_ && j_==rhs.j_; }
bool operator!=(const ColIterator& rhs) { return !operator==(rhs); }
double& operator*() {return array_[i_][j_];}
private:
MDarray & array_;
int i_;
int j_;
};
// a function
void mult2 (double & x) {
x *= 2;
}
int main () {
typedef std::vector<double>::iterator RowIterator;
int nRows = 5;
int nCols = 5;
ColIterator::MDarray array (nRows, std::vector<double>(nCols, 1));
// Apply function mult2 to column 3
int col = 3;
ColIterator beginCol (array, 0, col);
ColIterator endCol (array, nRows, col);
std::for_each(beginCol, endCol, mult2);
// Apply function mult2 to row 4
int row = 4;
RowIterator beginRow (array[row].begin());
RowIterator endRow (array[row].end());
std::for_each(beginRow, endRow, mult2);
// Check results
for (int i=0 ; i<nRows ; ++i) {
for (int j=0 ; j<nCols ; ++j) {
std::cout << " " << array[i][j];
}
std::cout << std::endl;
}
return 0;
}
答案 2 :(得分:0)
对于2D矢量:
行将很简单:
const std::vector<int>& getRow( const std::vector<std::vector<int>>& input, int rowIdx )
{
return input.at( rowIdx );
}
列有点棘手:
std::vector<int> getColumn( const std::vector<std::vector<int>>& input, int colIdx )
{
std::vector<int> output;
for ( unsigned i = 0; i < input.size(); ++i )
output.push_back( input.at( i ).at( colIdx ) );
return output;
}
这些函数基本上采用2D整数向量,并根据指定的索引返回行/列向量。
这是你尝试做的事情的基础(从我可以收集到的信息)。稍作修改将允许您有选择地将函数应用于行/列,而不仅仅是返回它们。
答案 3 :(得分:0)
如果你的多维向量是一个实际的多维向量,例如std::vector<std::vector<int>>
之类的东西,这是不建议的,那么你将不得不编写自己的迭代器。这不是很复杂。 Boost.Iterator具有可用于帮助实现它的概念。
如果你的多维向量是一个单一的向量,它的大小设置为维度(即宽度*高度)的乘积,这是处理它的首选方法,那么它就容易多了。可以使用Boost.Range提供的实用程序来完成。
这是使用Boost.Range的快速而肮脏的示例。 decltype
可以让它变得更漂亮。如果您的编译器不支持C ++ 11(特别是auto
),我建议不要使用它,因为代码变得非常难以阅读。
template<typename T>
boost::iterator_range<typename T::iterator>
GetRow(T& vec, typename T::size_type row, typename T::size_type w,
typename T::size_type h) {
return boost::make_iterator_range(
vec.begin() + (row * w),
vec.begin() + ((row + 1) * w)
);
}
template<typename T>
boost::strided_range<boost::iterator_range<typename T::iterator>>
GetColumn(T& vec, typename T::size_type col, typename T::size_type w,
typename T::size_type h) {
boost::iterator_range<typename T::iterator> range = boost::make_iterator_range(
vec.begin() + col,
vec.begin() + col + (h - 1) * w + 1
);
return boost::strided_range<boost::iterator_range<typename T::iterator>>(w, range);
}
然后使用这些函数非常简单,但如果编译器不支持auto
,它会变得非常难看。
const size_t WIDTH = 3;
const size_t HEIGHT = 3;
std::vector<int> vec(WIDTH * HEIGHT);
// Fill the first row with 1.
auto row = GetRow(vec, 0, WIDTH, HEIGHT);
for (auto it = row.begin(); it != row.end(); ++it) {
(*it) = 1;
}
// Fill the second column with 2.
auto col = GetColumn(vec, 1, WIDTH, HEIGHT);
for (auto it = col.begin(); it != col.end(); ++it) {
(*it) = 2;
}
// Contents of vec is:
// 1 2 1
// 0 2 0
// 0 2 0
您可能还想查看Boost.MultiArray,它是一个用于此类事情的库。它提供了您想要的功能,但它绝对不是最友好的库。