2013-04-17 3 views
2

Я хотел бы обрабатывать двумерные массивы C++ (матрицы) на C++, как я могу сделать с R-кадрами данных. Я имею в виду, что это позволяет указывать значения индексов для матриц.Пользовательские индексы с C++-матрицей

Например естественный ++ целочисленная матрица 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 . 
. 
. 
. 

Любые рекомендации будут высоко оценены.

+0

, так что бывшее 'Martix [0] [0] = 1' будет доступно посредством произвольного индекса, например,' Matrix [0] [5] '? – perreal

+0

Вам нужно будет определить собственный класс матрицы. Массивы в C++ являются примитивами для смежных блоков памяти, индексированных смежными целыми числами. – StoryTeller

+1

Схема индексации, которую вы имеете в виду здесь, совершенно неясна. –

ответ

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

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

+0

Спасибо за вашу поддержку! –

0

data.frame в R является по существу только фантазии оболочкой для list колонн, а list это - нелогично - близкий эквивалент std::map в С ++ (а не, как предполагает его название, из std::list).

Итак, другими словами, вы можете просто использовать ЬурейеЕ похожее на это аппроксимировать data.frame:

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

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

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


На самом деле, std::unordered_map. Для этого требуется C++ 11.

+0

Спасибо за ваш поддержка! –

0

Я хотел бы создать класс, который

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

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

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

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

+0

Спасибо за вашу поддержку! –

Смежные вопросы