我会创建一个类,其中包括以下功能:
- 将任意指定的索引转换为从0开始递增的索引
- 封装一个1D数组,以便您可以使用转换后的索引将其作为2D数组访问
下面是一个可行的示例:
#include <iostream>
#include <vector>
#include <algorithm>
#include <stdexcept>
#include <iterator>
#include <cassert>
using namespace std;
class DataFrame
{
vector<int> data;
public:
typedef vector<ssize_t> idx_t;
private:
idx_t rowIdx;
idx_t colIdx;
public:
DataFrame(const idx_t &rowIdx, const idx_t &colIdx)
: data(rowIdx.size() * colIdx.size())
, rowIdx(rowIdx)
, colIdx(colIdx)
{
assert(is_sorted(rowIdx.begin(), rowIdx.end()));
assert(is_sorted(colIdx.begin(), colIdx.end()));
}
int& operator()(int i, int j)
{
idx_t::iterator itI, itJ;
itI = lower_bound(rowIdx.begin(), rowIdx.end(), i);
if(rowIdx.end() == itI || i != *itI) throw out_of_range("could not find specified row");
itJ = lower_bound(colIdx.begin(), colIdx.end(), j);
if(colIdx.end() == itJ || j != *itJ) throw out_of_range("could not find specified col");
return data[distance(rowIdx.begin(), itI)*colIdx.size() +
distance(colIdx.begin(), itJ)];
}
vector<int> & getData() { return data; }
};
int main()
{
DataFrame::idx_t rI, cI;
rI.push_back(3);
rI.push_back(5);
cI.push_back(2);
cI.push_back(3);
cI.push_back(10);
DataFrame df(rI, cI);
df(3,2) = 1;
df(3,3) = 2;
df(3,10) = 3;
df(5,2) = 4;
df(5,3) = 5;
df(5,10) = 6;
ostream_iterator<int> out_it(cout, ", ");
copy(df.getData().begin(), df.getData().end(), out_it);
cout << endl;
return 0;
}
每行/列的任意索引都在一个向量中指定。为了保持一些性能,代码要求索引单调递增。(如果你使用的是 C++11,则在 ctor 中检查;如果你不使用 C++11,则没有 is_sorted
函数。此外,该代码不验证任意索引的唯一性。)
当你访问数据时,它只会在每个索引向量上进行二分搜索,以找到与任意索引匹配的位置,并将该位置用作对底层数据的相应索引。有一个简单的方法将 2D 索引转换成 1D 索引。
如果你需要担心这个问题,可以检查我的索引错误检查是否正确。
我会让你在const
访问器、各种构造函数等方面添加更多的健壮性/功能。如果你想将其推广到除2维之外的数组,我建议你创建一个类,仅用于将任意索引转换为基于0的索引,这将消除一些代码重复。还有其他方法可以将任意索引转换为基于0的索引,例如使用像其他人建议的map
。在这种情况下,存在一些问题,例如map
的创建者必须确保如果有10列,则[0,10)中的每个索引都恰好出现一次作为映射中的值。
Martix[0][0] = 1
现在可以通过任意索引来访问,例如Matrix[0][5]
? - perreal