Получить первый столбец матрицы, представленной вектором векторов

Предположим, я представляю матрицу foo значений с использованием std::vector:

int rows = 5;
int cols = 10;
auto foo = vector<vector<double>>(rows, vector<double>(cols));

Есть ли для меня умно простой способ получить vector<int> размера rows который содержит первый «столбец» foo:

{foo[0][0], foo[0][1], foo[0][2], foo[0][3], foo[0][4] }

Другими словами, могу ли я «транспонировать» foo так, чтобы выполнялись следующие три вещи:

foo_transpose.size() == cols
foo_transpose[0].size() == rows
foo_transpose[0] == {foo[0][0], foo[0][1], foo[0][2], foo[0][3], foo[0][4] }

Пояснительная записка

Есть несколько хороших предложений по альтернативным способам представления «матрицы». Когда я использую термин «матрица», я просто имею в виду, что каждый второй уровень vectorбудет такого же размера. Я не имею в виду, что я буду использовать эту структуру данных для операций типа линейной алгебры. Мне действительно нужен вектор векторов или структура данных, из которой вы можете «извлекать» одномерные векторы, потому что у меня есть функции, которые работают с такими векторами, как:

double sum(vector<double> const & v);

Это я называю по:

sum(foo[0]);

Это просто в особом случае я столкнулся с ситуацией, которую нужно сделать:

sum({foo[0][0], foo[0][1], foo[0][2], foo[0][3], foo[0][4] };

Для петлевого решения

Существует очевидное решение для петель, но я искал что-то более надежное и эффективное.

8

Решение

Как я упоминал в комментариях, нецелесообразно представлять матрицы с использованием вектора-вектора по нескольким причинам:

  1. Это неудобно для установки;
  2. Это трудно изменить;
  3. Локальность кэша плохая.

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

template <class T>
class SimpleMatrix
{
public:
SimpleMatrix( int rows, int cols, const T& initVal = T() );

// Size and structure
int NumRows() const                       { return m_rows; }
int NumColumns() const                    { return m_cols; }
int NumElements() const                   { return m_data.size(); }

// Direct vector access and indexing
operator const vector<T>& () const        { return m_data; }
int Index( int row, int col ) const       { return row * m_cols + col; }

// Get a single value
T & Value( int row, int col )       { return m_data[Index(row,col)]; }
const T & Value( int row, int col ) const { return m_data[Index(row,col)]; }
T & operator[]( size_t idx )        { return m_data[idx]; }
const T & operator[]( size_t idx ) const  { return m_data[idx]; }

// Simple row or column slices
vector<T> Row( int row, int colBegin = 0, int colEnd = -1 ) const;
vector<T> Column( int row, int colBegin = 0, int colEnd = -1 ) const;

private:
vector<T> StridedSlice( int start, int length, int stride ) const;

int m_rows;
int m_cols;

vector<T> m_data;
};

Этот класс в основном покрывает сахар вокруг одной функции — StridedSlice, Реализация этого:

template <class T>
vector<T> SimpleMatrix<T>::StridedSlice( int start, int length, int stride ) const
{
vector<T> result;
result.reserve( length );
const T *pos = &m_data[start];
for( int i = 0; i < length; i++ ) {
result.push_back(*pos);
pos += stride;
}
return result;
}

А все остальное довольно просто:

template <class T>
SimpleMatrix<T>::SimpleMatrix( int rows, int cols, const T& initVal )
: m_data( rows * cols, initVal )
, m_rows( rows )
, m_cols( cols )
{
}

template <class T>
vector<T> SimpleMatrix<T>::Row( int row, int colBegin, int colEnd ) const
{
if( colEnd < 0 ) colEnd = m_cols-1;
if( colBegin <= colEnd )
return StridedSlice( Index(row,colBegin), colEnd-colBegin+1, 1 );
else
return StridedSlice( Index(row,colBegin), colBegin-colEnd+1, -1 );
}

template <class T>
vector<T> SimpleMatrix<T>::Column( int col, int rowBegin, int rowEnd ) const
{
if( rowEnd < 0 ) rowEnd = m_rows-1;
if( rowBegin <= rowEnd )
return StridedSlice( Index(rowBegin,col), rowEnd-rowBegin+1, m_cols );
else
return StridedSlice( Index(rowBegin,col), rowBegin-rowEnd+1, -m_cols );
}

Обратите внимание, что Row а также Column Функции настроены таким образом, что вы можете легко запросить всю строку или столбец, но они немного мощнее, потому что вы можете разделить диапазон, передав один или два дополнительных параметра. И да, вы можете вернуть строку / столбец в обратном порядке, увеличив начальное значение больше конечного.

В эти функции не встроена проверка границ, но вы можете легко это добавить.

Вы также можете добавить что-то, чтобы вернуть срез области как другой SimpleMatrix<T>,

Повеселись.

18

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

Других решений пока нет …

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