如何旋转向量的向量

发布于 2024-11-07 05:02:08 字数 396 浏览 0 评论 0原文

我正在寻找一种优雅的方法来旋转向量的向量,最好使用STL算法或boost 示例数据看起来像这样

vector<vector<int> > vm;
vector<int> v;
v.push_back(1);
v.push_back(2);
vm.push_back(v);
v.clear();
v.push_back(3);
v.push_back(4);
vm.push_back(v);
v.clear();
v.push_back(5);
v.push_back(6);
vm.push_back(v);

1   2
3   4
5   6

我想获得像这样的整数向量的向量

1   3   5
2   4   6

I am looking for an elegant way to pivot a vector of vector prefarably using STL algorithms or boost
Sample data looks like this

vector<vector<int> > vm;
vector<int> v;
v.push_back(1);
v.push_back(2);
vm.push_back(v);
v.clear();
v.push_back(3);
v.push_back(4);
vm.push_back(v);
v.clear();
v.push_back(5);
v.push_back(6);
vm.push_back(v);

1   2
3   4
5   6

I want to get a vector of vectors of ints like this

1   3   5
2   4   6

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

青柠芒果 2024-11-14 05:02:08

我想最简单的解决方案就是编写一个简单的转置函数,其中包含两个循环:

std::vector<std::vector<int> > transpose(const std::vector<std::vector<int> > data) {
    // this assumes that all inner vectors have the same size and
    // allocates space for the complete result in advance
    std::vector<std::vector<int> > result(data[0].size(),
                                          std::vector<int>(data.size()));
    for (std::vector<int>::size_type i = 0; i < data[0].size(); i++) 
        for (std::vector<int>::size_type j = 0; j < data.size(); j++) {
            result[i][j] = data[j][i];
        }
    return result;
}

按值返回应该很容易被优化掉。我不认为使用任何标准函数会变得更简单或更有效,但我可能是错的。

另一种方法是将所有数据存储在一个平面向量中,然后使用i*row_length + j计算元素i, j的位置> 或类似的东西。这样,转置不涉及数据复制,而只是改变索引的计算。

I guess the simplest solution is just to write a simple transpose function with two loops in it:

std::vector<std::vector<int> > transpose(const std::vector<std::vector<int> > data) {
    // this assumes that all inner vectors have the same size and
    // allocates space for the complete result in advance
    std::vector<std::vector<int> > result(data[0].size(),
                                          std::vector<int>(data.size()));
    for (std::vector<int>::size_type i = 0; i < data[0].size(); i++) 
        for (std::vector<int>::size_type j = 0; j < data.size(); j++) {
            result[i][j] = data[j][i];
        }
    return result;
}

The return-by-value should be optimized away easily enough. I don't think it will get any simpler or more efficient by using any standard function, but I could be wrong.

An alternative approach would be to store all the data in one flat vector and then calculate the position of element i, j using i*row_length + j or something like that. This way, transposing involves no copying of data, but simply changing the calculation of the indices.

看看 Boost MultiArray。您可以创建子视图您的数据。还有 vnl_matrix 具有转置方法。

Look at Boost MultiArray. You can create sub-views of your data. There's also the vnl_matrix which has a transpose method.

£噩梦荏苒 2024-11-14 05:02:08

我将介绍一个转换行 -> 的包装器山口和山口 ->排。这将避免您复制所有数据。

#include <iostream>
#include <vector>

template<typename T>
class TwoDPivotWrapper
{
    public:
        // These two typedef's were done with std::vector
        // in mind. But with a small amount of effort I am
        // sure they can be generalized. They are solely to define
        // value_type (the data stored in the 2-D array).
        typedef typename T::value_type          OneDType;
        typedef typename OneDType::value_type   value_type;

        // A constructor that wraps a 2-D structure.
        TwoDPivotWrapper(T& o)
            : object(o)
        {}

        // A helper class used to store the row after the first array accesses.
        class Row
        {
            friend class TwoDPivotWrapper;
            Row(TwoDPivotWrapper& w, size_t r)
                : wrapper(w)
                , row(r)
            {}

            TwoDPivotWrapper&    wrapper;  
            size_t               row;

            public:
                value_type operator[](size_t col)
                {                    
                    return wrapper.get(row,col);
                }
        };

        // The operator [] returns a Row object that overloads
        // the operator[] for the next dimension.
        Row operator[](size_t row)              {return Row(*this, row);}

        // Generic get function used to access elements.
        // Notice we swap the row/col around when accessing
        // the underlying object.
        value_type get(size_t row, size_t col)  {return object[col][row];}

    private:
        T&  object;
};

典型用法是:

int main()
{
    typedef std::vector<std::vector<int> >      TwoDVector;

    TwoDVector  data(3,std::vector<int>(2,0));

    data[0][0]  = 1; data[0][1]  = 2;
    data[1][0]  = 3; data[1][1]  = 4;
    data[2][0]  = 5; data[2][1]  = 6;

    TwoDPivotWrapper<TwoDVector>               wrapper(data);
    std::cout << wrapper[0][0] << wrapper[0][1] << wrapper[0][2] << "\n";
    std::cout << wrapper[1][0] << wrapper[1][1] << wrapper[1][2] << "\n";
}

I would introduce a wrapper that converts row -> col and col -> row. This will prevent you having to copy all the data.

#include <iostream>
#include <vector>

template<typename T>
class TwoDPivotWrapper
{
    public:
        // These two typedef's were done with std::vector
        // in mind. But with a small amount of effort I am
        // sure they can be generalized. They are solely to define
        // value_type (the data stored in the 2-D array).
        typedef typename T::value_type          OneDType;
        typedef typename OneDType::value_type   value_type;

        // A constructor that wraps a 2-D structure.
        TwoDPivotWrapper(T& o)
            : object(o)
        {}

        // A helper class used to store the row after the first array accesses.
        class Row
        {
            friend class TwoDPivotWrapper;
            Row(TwoDPivotWrapper& w, size_t r)
                : wrapper(w)
                , row(r)
            {}

            TwoDPivotWrapper&    wrapper;  
            size_t               row;

            public:
                value_type operator[](size_t col)
                {                    
                    return wrapper.get(row,col);
                }
        };

        // The operator [] returns a Row object that overloads
        // the operator[] for the next dimension.
        Row operator[](size_t row)              {return Row(*this, row);}

        // Generic get function used to access elements.
        // Notice we swap the row/col around when accessing
        // the underlying object.
        value_type get(size_t row, size_t col)  {return object[col][row];}

    private:
        T&  object;
};

Typical usage would be:

int main()
{
    typedef std::vector<std::vector<int> >      TwoDVector;

    TwoDVector  data(3,std::vector<int>(2,0));

    data[0][0]  = 1; data[0][1]  = 2;
    data[1][0]  = 3; data[1][1]  = 4;
    data[2][0]  = 5; data[2][1]  = 6;

    TwoDPivotWrapper<TwoDVector>               wrapper(data);
    std::cout << wrapper[0][0] << wrapper[0][1] << wrapper[0][2] << "\n";
    std::cout << wrapper[1][0] << wrapper[1][1] << wrapper[1][2] << "\n";
}
吻安 2024-11-14 05:02:08

如果您要使用 C++ 进行大量线性代数计算,您应该查看 Boost.uBlas

#include <boost/numeric/ublas/matrix.hpp>

template <class M>
void printMatrix(const M& m)
{
    for (size_t i=0; i<m.size1(); ++i)
    {
        for (size_t j=0; j<m.size2(); ++j)
            std::cout << m(i,j) << " ";
        std::cout << std::endl;
    }
}

int main()
{
    namespace ublas = boost::numeric::ublas;
    typedef ublas::matrix<double> Matrix;
    Matrix A(3, 2);

    // Fill matrix A with incrementing values
    double counter = 0.0;
    for (size_t i=0; i<A.size1(); ++i)
        for (size_t j=0; j<A.size2(); ++j)
            A(i,j) = ++counter;

    printMatrix(A);
    std::cout << std::endl;

    // Transpose A and store it in B
    Matrix B = ublas::trans(A);
    printMatrix(B);

    return 0;
}

If you're going to be doing lots of linear algebra in C++, you should check out Boost.uBlas.

#include <boost/numeric/ublas/matrix.hpp>

template <class M>
void printMatrix(const M& m)
{
    for (size_t i=0; i<m.size1(); ++i)
    {
        for (size_t j=0; j<m.size2(); ++j)
            std::cout << m(i,j) << " ";
        std::cout << std::endl;
    }
}

int main()
{
    namespace ublas = boost::numeric::ublas;
    typedef ublas::matrix<double> Matrix;
    Matrix A(3, 2);

    // Fill matrix A with incrementing values
    double counter = 0.0;
    for (size_t i=0; i<A.size1(); ++i)
        for (size_t j=0; j<A.size2(); ++j)
            A(i,j) = ++counter;

    printMatrix(A);
    std::cout << std::endl;

    // Transpose A and store it in B
    Matrix B = ublas::trans(A);
    printMatrix(B);

    return 0;
}
浮光之海 2024-11-14 05:02:08

它绝对必须是向量的向量吗?

如果没有,那么您可能可以在行*列元素的常规向量上实现包装器。

类似于:

class Vector
{
public:
    int operator[]( int index )
    {
        return 1;
    }
    friend class Wrapper;
private:
    Vector( std::vector<int> & vector, int index, int numElements );

    std::vector<int> v_;
    int index_;
    int numElements_;
};

class Wrapper
{
public:
    Vector operator[](int index)
    {
        return Vector( v_, index, numColumns_ );
    }

    Wrapper( int numRows, int numColumns);
    void setNumRows( int numRows );
    void setNumColumns( int numColumns );
private:
    std::vector<int> v_;
    int numRows_;
    int numColumns_;
};

并在 main 中:

Wrapper w;

int i = w[1][1];

编辑:

Vector 类将表示行或列数据。
它需要线性化矩阵、矩阵几何形状(行数和列数)以及它代表的行/列作为参数。

用铅笔和纸试试这个:
1. 将 3x4 矩阵的元素写成矩阵形式

11 12 13 14
21 22 23 24
31 32 33 34

  1. 以线性化方式编写它们:

11 12 13 14 21 22 23 24 31 32 33 34

矩阵形式的元素索引与其线性化形式的索引之间存在简单的关系,该关系取决于矩阵的几何形状。

  1. 如果您希望 Vector “包含”元素 21 22 23 24 (或 12 22 32),那么您需要在运算符 [] (int 索引)中实现一些逻辑,该逻辑将确定 Vector 中元素的基础向量中的索引[指数]。

假设您的 Vector 需要引用矩阵中的第二列(即 12 22 32)。
然后:
- 向量中的第一项(即 Vector[1])是线性化矩阵中的第二个元素
- 向量中的第二项 22 是基础向量中的第 6 个元素
- 向量中的第三项 32 是 v_ 的第 10 个元素

现在,用铅笔和纸对矩阵的第三列(元素 13 23 33)执行相同的操作。
查看第二列的基础向量中的索引(分别为 2、6 和 10)与第三列的索引之间是否存在相似性。

Does it absolutely have to be a vector of vectors?

If not, then you could probably implement a wrapper over a regular vector of rows*columns elements.

Something like:

class Vector
{
public:
    int operator[]( int index )
    {
        return 1;
    }
    friend class Wrapper;
private:
    Vector( std::vector<int> & vector, int index, int numElements );

    std::vector<int> v_;
    int index_;
    int numElements_;
};

class Wrapper
{
public:
    Vector operator[](int index)
    {
        return Vector( v_, index, numColumns_ );
    }

    Wrapper( int numRows, int numColumns);
    void setNumRows( int numRows );
    void setNumColumns( int numColumns );
private:
    std::vector<int> v_;
    int numRows_;
    int numColumns_;
};

and in main:

Wrapper w;

int i = w[1][1];

EDIT:

The Vector class will represent the row or column data.
It needs, as parameters, the linearized matrix, the matrix geometry(number of rows and columns) and what row/column it represents.

Try this with pencil and paper:
1. write the elements of a 3x4 matrix in matrix form

11 12 13 14
21 22 23 24
31 32 33 34

  1. write them in a linearized fashion:

11 12 13 14 21 22 23 24 31 32 33 34

There is a simple relation between an element's indices from the matrix form and its index in the linearized form which depends on the matrix geometry.

  1. if you want a Vector to "contain" elements 21 22 23 24 (or 12 22 32) then you need to implement some logic in your operator [] (int index) that will determine the index in the underlying vector of the element from Vector[index].

Say your Vector needs to reference the second column from the matrix (i.e. 12 22 32).
Then:
- the first item in the vector (i.e. Vector[1]) is the second element in the linearized matrix
- the second item in the vector, 22, is the 6th element from the underlying vector
- the third item in the vector, 32, is the 10th element of v_

Now, with pencil and paper do the same for the third column of the matrix( elements 13 23 33).
See if you spot any similarity between the indexes in the underlying vector for the second column (which were 2, 6 and 10) and the indexes you find for the third column.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文