Пользовательские индексы с матрицей C ++

Я хотел бы рассматривать двумерные массивы (матрицы) 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 .
.
.
.

Любой совет будет высоко ценится.

2

Решение

Если вы хотите переключать столбцы, строки матриц, вы можете использовать некоторую косвенность:

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

или вы можете написать класс для обработки этого косвенного для вас.

3

Другие решения

data.frame в R, по сути, просто модная обертка для list столбцов и list это — нелогично — близкий эквивалент std::map1 в C ++ (а не, как следует из названия, std::list).

Другими словами, вы можете просто использовать typedef, подобный этому, чтобы приблизить data.frame:

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

… Но классы R на самом деле немного более мощные, поскольку они в некоторой степени универсальны, поддерживают разные типы внутри фрейма данных, проверяют, что все строки имеют одинаковую длину, и разрешают именованный доступ для столбцов и строк. И, наконец, давайте не будем забывать, что R поддерживает работу с фреймами данных, их красивую печать, эффективную загрузку и сохранение.

В зависимости от того, что вы нужно, конечно, нет необходимости копировать все это в C ++, но определенно полезно обернуть вашу структуру внутри класса и предоставить надлежащий интерфейс для доступа к ней.


1 На самом деле, std::unordered_map, Это требует C ++ 11.

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 функция. Кроме того, этот код не проверяет уникальность произвольных индексов.)

Когда вы получаете доступ к данным, он просто выполняет двоичный поиск по каждому вектору индексов, чтобы найти позицию в векторе, которая соответствует произвольному индексу, и использует эту позицию в качестве соответствующего индекса для базовых данных. Существует простое преобразование из 2D-индексов в 1D-индекс.

Вы можете проверить, что моя проверка ошибок индекса верна для всех комбинаций плохих / хороших индексов, если вам нужно беспокоиться об этом.

Я оставлю это вам, чтобы добавить больше надежности / функциональности с точки зрения const методы доступа, различные конструкторы и т. д. Если вы хотите обобщить это для массивов измерения, отличных от 2, я рекомендую вам создать класс для простого преобразования произвольного индекса в индекс на основе 0, и это избавит от некоторых повторений кода. иметь. Существуют также другие способы преобразования произвольного индекса в индекс на основе 0, например, с помощью map как другие предложили. В этом случае, однако, есть некоторые проблемы, такие как создатель map Было бы необходимо убедиться, что если есть, скажем, 10 столбцов, каждый индекс в [0, 10) отображается ровно один раз в качестве значения на карте.

0
По вопросам рекламы [email protected]