我正在尝试实现一个简单的类似matlab的数组(现在实际上只有一个维度),我尝试做的是实现以下matlab代码:
a=1:10;
ind=find(a>5);
a[ind]=5;
我知道std有valarray通过切片数组来做到这一点。我不太了解它的细节。代码是:
#include <iostream>
using namespace std;
template <typename T> class array
{
public:
int m,n; //two dimensional at most
T *pdata;
//construct the array
array(){m=n=0;pdata=NULL;} //default is empty matrix
array(T a){m=n=1;pdata=new T[1];*pdata=a;} //array for scalar: array a=10;
array(int m0,int n0=1) {m=m0;n=1;pdata=new T[m];}
array(const array& a,int len=-1);
//destructor
~array() {delete []pdata;}
//operator overloading
array<T>& operator+=(T s);
T& operator[](int i) {return pdata[i];}
array<T>& operator[](array<int> ind);
array<T>& operator=(const array<T>& a);
array<T>& operator=(T a) {for(int i=0;i<m;i++) pdata[i]=a;return *this;}
array<bool> operator>(T a);
array<bool> operator<(T a);
array<bool> operator==(T a);
};
//copy a part of the other array
template <typename T> array<T>::array<T>(const array<T>& a,int len)
{
if(len==-1) len=a.m*a.n;
if(len==0) {m=0;n=0;pdata=NULL;}
if(len>0)
{
m=len;n=1;
pdata=new T[len];
for(int i=0;i<len;i++) pdata[i]=a.pdata[i];
}
}
template <typename T> array<T>& array<T>::operator +=(T s)
{
for(int i=0;i<m*n;i++) pdata[i]+=s;
return *this;
}
//this function does not meet the purpose, it returns a reference to a temp obj
template <typename T> array<T>& array<T>::operator[](array<int> ind)
{
array<T> ret(ind.m,ind.n);
for(int i=0;i<ind.m*ind.n;i++)
{
ret.pdata[i] = pdata[ind.pdata[i]];
}
return ret;
}
template <typename T> array<bool> array<T>::operator>(T a)
{
array<bool> res(m*n);
for(int i=0;i<m*n;i++) res.pdata[i]=pdata[i]>a;
return res;
}
//helper function
array<int> find(array<bool> a)
{
array<int> ret(a.m,a.n); //first use the same size space
int len=0;
for(int i=0;i<a.m*a.n;i++)
{
if(a.pdata[i]) {ret.pdata[len]=i;len++;}
}
return array<int>(ret,len);
}
/*ostream& operator<<(array<T>& a)
{
ostream os;
for(int i=0;i<a.m*a.n;i++) os>>a[i]>>'\t';
return os;
}*/
int main()
{
array<float> a(10);
for(int i=0;i<10;i++) a[i]=i;
for(i=0;i<10;i++) cout<<a[i]<<'\t';
cout<<endl;
array<int> ind=find(a>5);
for(i=0;i<ind.m;i++) cout<<ind[i]<<'\t';
cout<<endl;
a[ind]=5;//this will not work on the original array
//how do we support this????undefined
for(i=0;i<10;i++) cout<<a[i]<<'\t';
cout<<endl;
return 0;
}
由于我们正在处理临时数组,因此最终的a根本没有改变。 我知道函数运算符“&gt;未正确实现,但我不知道如何执行此操作。任何人都可以给我一个提示?谢谢
答案 0 :(得分:1)
我会创建一个ArraySlice
类,并从operator []
返回一个实例。此类将引用原始Array
,并且需要将大多数成员重新实现为Array
的前向调用。例如,ArraySlice::operator[]
会使用适当的索引调用Array::operator[]
。
答案 1 :(得分:0)
我认为对于共享数组,最好的解决方案是为原始(完整)矩阵和“视图”提供单一类型。 通过参数化元素访问,您可以为两者使用相同的通用代码,如果在类中添加一个可选的std :: vector元素,它将包含原始完整矩阵的实际数据,那么内存处理将自动进行。
这是这个想法的一个小实现...对于选择我使用了std::vector
个整数对;分配给ArraySelection
将使用元素访问运算符,因此它既适用于原始矩阵,也适用于视图。
主程序分配10x10矩阵,然后使用坐标为偶数/偶数,偶数/奇数,奇数/偶数和奇数/奇数的元素创建四个不同的5x5视图。 这些视图设置为4个不同的常量值。 然后在完整矩阵上进行选择,并对所选元素进行分配。最后打印出原始的完整矩阵。
#include <stdexcept>
#include <vector>
#include <functional>
#include <algorithm>
#include <stdio.h>
typedef std::vector< std::pair<int, int> > Index;
template<typename T>
struct Array;
template<typename T>
struct ArraySelection
{
Array<T>& a;
Index i;
ArraySelection(Array<T>& a)
: a(a)
{
}
ArraySelection& operator=(const T& t)
{
for (int j=0,n=i.size(); j<n; j++)
a(i[j].first, i[j].second) = t;
return *this;
}
};
template<typename T>
struct Array
{
int rows, cols;
std::vector<T*> rptr;
int step;
std::vector<T> data; // non-empty if data is owned
T& operator()(int r, int c)
{
return rptr[r][c * step];
}
Array(int rows, int cols,
Array *parent = NULL,
int row0=0, int rowstep=1,
int col0=0, int colstep=1)
: rows(rows), cols(cols), rptr(rows)
{
if (parent == NULL)
{
// Owning matrix
data.resize(rows*cols);
for (int i=0; i<rows; i++)
rptr[i] = &data[i*cols];
step = 1;
}
else
{
// View of another matrix
for (int i=0; i<rows; i++)
rptr[i] = &((*parent)(row0 + i*rowstep, col0));
step = colstep;
}
}
template<typename F>
ArraySelection<T> select(const F& f)
{
Index res;
for (int i=0; i<rows; i++)
for (int j=0; j<cols; j++)
if (f((*this)(i, j)))
res.push_back(std::make_pair(i, j));
ArraySelection<T> ar(*this);
ar.i.swap(res);
return ar;
}
// Copy construction of a full matrix makes a full matrix,
// Copy construction of a view creates a view
Array(const Array& other)
: rows(other.rows), cols(other.cols), rptr(other.rptr), step(other.step)
{
if (other.data)
{
data = other.data;
for (int i=0; i<rows; i++)
rptr[i] = &data[i*cols];
}
}
// Assignment is element-by-element optionally with conversion
template<typename U>
Array& operator=(const Array<U>& other)
{
if (other.rows != rows || other.cols != cols)
throw std::runtime_error("Matrix size mismatch");
for(int i=0; i<rows; i++)
for (int j=0; j<cols; j++)
(*this)(i, j) = other(i, j);
return *this;
}
};
int main()
{
Array<double> a(10, 10);
Array<double> a00(5, 5, &a, 0, 2, 0, 2);
Array<double> a01(5, 5, &a, 0, 2, 1, 2);
Array<double> a10(5, 5, &a, 1, 2, 0, 2);
Array<double> a11(5, 5, &a, 1, 2, 1, 2);
for (int i=0; i<5; i++)
for (int j=0; j<5; j++)
{
a00(i, j) = 1.1;
a01(i, j) = 2.2;
a10(i, j) = 3.3;
a11(i, j) = 4.4;
}
a.select(std::binder2nd< std::greater<double> >(std::greater<double>(), 3.5)) = 0;
for (int i=0; i<10; i++)
{
for (int j=0; j<10; j++)
{
printf(" %0.3f", a(i, j));
}
printf("\n");
}
return 0;
}
答案 2 :(得分:0)
安德烈,谢谢你的提示。你所说的大部分都是有道理的,真的很有帮助。我创建另一个ind_array并保留原始数组的地址,现在它可以工作了! 唯一的变化是operator []现在返回ind_array。并且operator = for ind_array被定义为执行实际赋值。 (为了简单起见,我现在删除了第二个维度)
以下是修改后的代码:
#include <iostream>
using namespace std;
template <typename T> class ind_array;
template <typename T> class array
{
public:
int len; //two dimensional at most
T *pdata;
//construct the array
array(){len=0;pdata=NULL;} //default is empty matrix
//array(T a){len=1;pdata=new T[1];*pdata=a;} //array for scalar: array a=10;
array(int m0) {len=m0;pdata=new T[len];}
array(const array& a,int len0=-1);
//destructor
~array() {delete []pdata;}
int size() const {return len;}
//operator overloading
array<T>& operator+=(T s);
T& operator[](int i) {return pdata[i];}
ind_array<T> operator[](const array<int>& ind);//{return (ind_array(ind,pdata));}
array<T>& operator=(const array<T>& a);
array<T>& operator=(T a) {for(int i=0;i<len;i++) pdata[i]=a;return *this;}
array<bool> operator>(T a);
array<bool> operator<(T a);
array<bool> operator==(T a);
};
//Index array or similar indirect-array as in valarray
//this class shall keeps the array's address and the index
template <typename T> class ind_array
{
array<int> ind; //an index array
T* ptr; //a pointer to the original data
public:
int size() const {return ind.size();}
void operator=(T a){for(int i=0;i<size();i++) ptr[ind[i]]=a;} //assignment a value to a subarray
//how to construct the indx array then?
//according to valarry, the default constructor shall be prohibited
ind_array(const array<int>& indx,T* pt):ind(indx),ptr(pt){} //default constructor
};
//copy a part of the other array
template <typename T> array<T>::array<T>(const array<T>& a,int len0)
{
if(len0==-1) len0=a.len;
if(len0==0) {len=0;pdata=NULL;}
if(len0>0)
{
len=len0;
pdata=new T[len];
for(int i=0;i<len;i++) pdata[i]=a.pdata[i];
}
}
template <typename T> array<T>& array<T>::operator +=(T s)
{
for(int i=0;i<len;i++) pdata[i]+=s;
return *this;
}
//this function does not meet the purpose, it returns a reference to a temp obj
//now we change it to return a indx_array which stores the original array's address
template <typename T> ind_array<T> array<T>::operator[](const array<int>& ind)
{
/*array<T> ret(ind.len);
for(int i=0;i<ind.len;i++)
{
ret.pdata[i] = pdata[ind.pdata[i]];
}
return ret;*/
return (ind_array<T>(ind,pdata)); //call the constructor
}
template <typename T> array<bool> array<T>::operator>(T a)
{
array<bool> res(len);
for(int i=0;i<len;i++) res.pdata[i]=pdata[i]>a;
return res;
}
//helper function
array<int> find(array<bool> a)
{
array<int> ret(a.len); //first use the same size space
int len=0;
for(int i=0;i<a.len;i++)
{
if(a.pdata[i]) {ret.pdata[len]=i;len++;}
}
return array<int>(ret,len);
}
/*ostream& operator<<(array<T>& a)
{
ostream os;
for(int i=0;i<a.m*a.n;i++) os>>a[i]>>'\t';
return os;
}*/
int main()
{
array<float> a(10);
for(int i=0;i<10;i++) a[i]=i;
for(i=0;i<10;i++) cout<<a[i]<<'\t';
cout<<endl;
array<int> ind=find(a>5);
for(i=0;i<ind.len;i++) cout<<ind[i]<<'\t';
cout<<endl;
a[ind]=5;//this will not work on the original array
//how do we support this????undefined
for(i=0;i<10;i++) cout<<a[i]<<'\t';
cout<<endl;
return 0;
}