【问题标题】:Custom indexes with C++ matrix使用 C++ 矩阵的自定义索引
【发布时间】:2026-02-16 09:40:01
【问题描述】:

我想在 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 .
.
.
.

任何建议将不胜感激。

【问题讨论】:

  • 所以以前的Martix[0][0] = 1 将被任意索引访问,例如Matrix[0][5]?
  • 您需要定义一个自定义矩阵类。 C++ 中的数组是由连续整数索引的连续内存块的原语。
  • 这里您想到的索引方案完全不清楚。
  • 如果您没有使用过 R 和 C++,那就不清楚了!我认为他希望能够使用自定义索引来访问矩阵。比如,使用 matrix["6"]["5] 或 matrix ["6","5"] 来访问第 4 行第 1 列的单元格。
  • 如果是TooTone所描述的那样,你需要一个索引xlat中介,这应该不难实现(我想这样的事情至少也是R中需要的init级别(我的一种语言)了解zilch)。

标签: c++ matrix indices


【解决方案1】:

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

 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];

或者你可以编写一个类来为你处理这种间接。

【讨论】:

    【解决方案2】:

    R 中的 data.frame 本质上只是对列的 list 的精美包装,而 list 不合逻辑地与 C++ 中的 std::map1 非常相似(而不是顾名思义,std::list)。

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

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

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

    根据的需要,当然没有必要在 C++ 中复制所有这些,但将你的结构包装在一个类中并提供一个适当的接口来访问它绝对是有益的。


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

    【讨论】:

      【解决方案3】:

      我会创建一个类

      • 将任意指定索引转换为从 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 函数。此外,此代码不会验证任意的唯一性指数。)

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

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

      我会留给您在const 访问器、各种构造函数等方面添加更多的健壮性/功能。如果您想将其推广到除 2 之外的维度数组,我建议您为只需将任意索引转换为基于 0 的索引,这将消除我的一些代码重复。还有其他方法可以将任意索引转换为基于 0 的索引,例如像其他人建议的那样使用map。但是在这种情况下,存在一些问题,例如 map 的创建者必须确保如果有 10 列,则 [0, 10) 中的每个索引作为映射中的值恰好出现一次。

      【讨论】:

        最近更新 更多