Get the first column of a matrix represented by a vector of vectors

后端 未结 1 1532
失恋的感觉
失恋的感觉 2020-11-27 19:36

Suppose I\'m representing a matrix foo of values using std::vector:

int rows = 5;
int cols = 10;    
auto foo = vector

        
相关标签:
1条回答
  • 2020-11-27 20:33

    As I mentioned in the comments, it's not practical to represent matrices using vector-of-vector for a few reasons:

    1. It is fiddly to set up;
    2. It is difficult to change;
    3. Cache locality is bad.

    Here is a very simple class I have created that will hold a 2D matrix in a single vector. This is pretty much how software like MATLAB does it... albeit a huge simplification.

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

    This class is basically sugar-coating around a single function -- StridedSlice. The implementation of that is:

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

    And the rest is pretty straight-forward:

    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 );
    }
    

    Note that the Row and Column functions are set up in such a way that you can easily request an entire row or column, but are a little more powerful because you can slice a range by passing one or two more parameters. And yes, you can return the row/column in reverse by making your start value larger than your end value.

    There is no bounds-checking built into these functions, but you can easily add that.

    You could also add something to return an area slice as another SimpleMatrix<T>.

    Have fun.

    0 讨论(0)
提交回复
热议问题