Obtenga la primera columna de una matriz representada por un vector de vectores

Supongamos que estoy representando una matriz foo de valores usando std::vector :

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

¿Hay una manera ingeniosamente simple para obtener un vector de rows de tamaño que contiene la primera “columna” de foo:

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

Dicho de otra manera, ¿puedo “transponer” foo para que las siguientes tres cosas sean verdaderas?

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

Nota aclaratoria

Hay algunas buenas sugerencias para formas alternativas de representar una “matriz”. Cuando uso el término “matriz” simplemente quiero decir que cada uno de los vector segundo nivel tendrá el mismo tamaño. No pretendo sugerir que usaré esta estructura de datos para operaciones de tipo álgebra lineal. De hecho, NECESITO un vector de vectores, o una estructura de datos desde la que pueda “sacar” vectores 1D, porque tengo funciones que operan en vectores como:

 double sum(vector const & v); 

Que llamo por:

 sum(foo[0]); 

Es solo en un caso especial que llegué a una situación que necesito hacer:

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

Para la solución Loop

Existe una solución obvia para el bucle, pero estaba buscando algo más sólido y eficiente.

Como mencioné en los comentarios, no es práctico representar matrices usando vector-de-vector por algunas razones:

  1. Es difícil de configurar;
  2. Es difícil de cambiar;
  3. La localidad de caché es mala.

Aquí hay una clase muy simple que he creado que tendrá una matriz 2D en un solo vector. Esto es más o menos como lo hace un software como MATLAB … aunque una gran simplificación.

 template  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& () 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 Row( int row, int colBegin = 0, int colEnd = -1 ) const; vector Column( int row, int colBegin = 0, int colEnd = -1 ) const; private: vector StridedSlice( int start, int length, int stride ) const; int m_rows; int m_cols; vector m_data; }; 

Esta clase es básicamente una capa de azúcar alrededor de una función única: StridedSlice . La implementación de eso es:

 template  vector SimpleMatrix::StridedSlice( int start, int length, int stride ) const { vector 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; } 

Y el rest es bastante directo:

 template  SimpleMatrix::SimpleMatrix( int rows, int cols, const T& initVal ) : m_data( rows * cols, initVal ) , m_rows( rows ) , m_cols( cols ) { } template  vector SimpleMatrix::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  vector SimpleMatrix::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 ); } 

Tenga en cuenta que las funciones de Row y Column están configuradas de tal manera que puede solicitar fácilmente una fila o columna completa, pero son un poco más potentes porque puede cortar un rango al pasar uno o dos parámetros más. Y sí, puede devolver la fila / columna en reversa haciendo que su valor de inicio sea mayor que su valor final.

No hay controles de límites integrados en estas funciones, pero puede agregarlo fácilmente.

También podría agregar algo para devolver un sector como otro SimpleMatrix .

Que te diviertas.