使用C ++矩阵的自定义索引

时间:2013-04-17 17:22:51

标签: c++ matrix indices

我想在C ++中处理C ++二维数组(矩阵),就像我可以用R数据帧一样。我的意思是能够指定矩阵的索引值。

例如,自然C ++整数矩阵是这样的:

  0 1 2 3 4 ...
0 1 0 1 0 .
1 3 . . .
2 8 . .
3 . .
4 .
.
.
.

我想在矩阵中指定索引,所以它们就像这样,例如:

  5 7 8 13 24 ...
0 1 0 1 0 .
1 3 . . .
2 8 . .
6 . .
8 .
.
.
.

任何建议都将不胜感激。

3 个答案:

答案 0 :(得分:3)

如果要切换列,矩阵行,可以使用一些间接:

 indexTable[0][0] = 0; // map row index 0 to 0
 indexTable[1][0] = 5; // map column index 0 to 5

并像这样使用它:

 value = matrix[indexTable[0][RowIndex]][indexTable[1][ColumnIndex];

或者您可以编写一个类来为您处理此间接。

答案 1 :(得分:0)

R中的data.frame基本上只是list列的花哨包装,而list是 - 不合逻辑 - 相当于std::map 1 in C ++(而不是顾名思义,是std::list)。

换句话说,您可以使用与此类似的typedef来近似data.frame

typedef std::map<int, std::vector<int>> data_frame;

...但是R类实际上相当强大,因为它们在某种程度上是通用的,支持数据框内的不同类型,检查所有行是否具有相同的长度并允许列和行的命名访问。最后,我们不要忘记R支持使用数据框,漂亮地打印它们并有效地加载和保存它们。

根据的需要,当然不必在C ++中复制所有这些内容,但将结构封装在一个类中并提供适当的接口来访问它肯定是有益的。


1 实际上是std::unordered_map。这需要C ++ 11。

答案 2 :(得分:0)

我会创建一个

的类
  • 将任意指定的索引转换为基于0的增量索引
  • 包装一维数组,以便您可以使用转换后的索引
  • 将其作为二维数组进行访问

一个工作示例看起来像这样

#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功能。此外,这段代码没有& #39; t验证任意索引的唯一性。)

当您访问数据时,它只对每个索引向量进行二分查找,以找到向量中与任意索引匹配的位置,并将该位置用作基础数据的相应索引。可以从2D索引到1D索引进行简单的转换。

如果您需要担心,可能需要检查我的索引错误检查对于错误/良好索引的所有组合是否正确。

我会留给您,以便在const访问者,各种构造函数等方面添加更多健壮性/功能。如果您想将此概括为2以外的维度数组,我建议您创建一个类,只是将任意索引转换为基于0的索引,这将摆脱我的一些代码重复。还有其他方法可以将任意索引转换为基于0的索引,例如使用其他人建议的map。但是,在这种情况下,存在一些问题,例如map的创建者必须确保如果有10个列,则[0,10]中的每个索引在地图中只显示一次作为值。