子数组通过索引:如何
subarray through index: how to?
我试图实现一个简单的类似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根本没有改变,因为我们正在处理一个临时数组。我知道函数运算符">没有正确实现,但我不知道如何做到这一点。有人能给我点提示吗?由于
我将创建一个ArraySlice
类,并从operator []
返回一个实例。该类将有对原始Array
的引用,并且需要将大多数成员重新实现为对Array
的前向调用。例如,ArraySlice::operator[]
将使用适当的索引调用Array::operator[]
。
我认为对于共享数组,最好的解决方案是对原始(完整)矩阵和"视图"都具有单一类型。通过参数化元素访问,你可以让相同的泛型代码为两者工作,如果你在类中添加一个可选的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;
}
Andrea,谢谢你的提示。你说的大部分都很有道理,也很有帮助。我创建了另一个ind_array并保留了原始数组的地址,现在它工作了!唯一的变化是操作符[]现在返回ind_array。并且为ind_array定义了operator=来执行实际赋值。(为了简单起见,我现在删除了第二次元)
下面是修改后的代码:
#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;
}
- 给定一个向量,如何找到该向量的所有子集和的原始索引
- 如何为圆环创建索引
- 如何查找哪个类对象位于数组的特定索引上(多态性)
- 如何检查类实例向量的索引是否为空
- C++17:如何在并行 STL 中获取工作项的索引
- 如何对存储为"Compressed Sparse Row"的矩阵进行稀疏矩阵索引?
- 如何根据排序索引的向量对 std::index 集进行排序?
- 编译器(Visual C++)如何优化按索引访问矢量元素?
- 我们应该如何使用枚举类进行索引(或者我们应该更好地避免这种情况)?
- c++ 如何在数组的开头添加值并为其编制索引?
- CPtrList - 如何获取元素的索引?
- 如何索引转换后的用户数据值?
- 如何摆脱导入的 make 项目中的 Eclipse 索引器"Type std::... could not be resolved"错误
- 如何更好地表示 6 个整数键而不是作为 6 维数组的索引?
- 在矢量中使用擦除时双重释放或损坏(快速顶部).如何擦除一个矢量的几个项目知道它们的索引?
- 如何索引指向数组 [queue] 的指针数组
- 如何索引和修改OpenCV矩阵
- 我如何索引树在SQLite表
- 如何索引到点云的点
- 如何索引到c++ shared_ptr/unique_ptr数组