1

我有一个简单的点结构

struct mypoint
{
    int x;
    int y;
};

和一个vector_mypoint

vector<mypoint> myvector;

如果我想创建一个int包含所有点坐标的向量(即x1, y1, x2, y2, x3, y3, ...),我可以通过以下方式轻松完成

vector<mypoint>::iterator pt, ptend(myvector.end());
vector<int> newvector;

for(pt=myvector.begin(); pt!=ptend; ++pt)
{
    newvector.push_back(pt->x);
    newvector.push_back(pt->y);
}

有没有办法使用 C++11 在一行(或两行)代码中获得相同的结果?

4

6 回答 6

4
std::vector<int> extractIntsFromPoints(const std::vector<mypoint>& pointVector)
{
    std::vector<int> retVector;    
    for (const auto& element : pointVector)
    {
        retVector.push_back(element.x);
        retVector.push_back(element.y);
    }
    return retVector;
}

在需要 int 向量的地方调用此函数。我加入了基于范围的 for 循环,使其成为额外的 C++11。

于 2013-03-27T15:48:49.107 回答
3

由于您使用的是 C++11,因此您可以使用新的 for 语法。

vector<int> newvector;

for( const auto &pt : myvector)
{
    newvector.push_back(pt.x);
    newvector.push_back(pt.y);
}
于 2013-03-27T15:47:56.510 回答
1

从帖子中窃取:C++ std::transform vector of pairs->first to new vector

vector<int> items;
std::transform(pairs.begin(), 
               pairs.end(), 
               std::back_inserter(items), 
               [](const std::pair<int, int>& p) { return p.first; });
于 2013-03-27T15:49:55.397 回答
1

这是大约 4 行,使用 lambda:

vector<mypoint> points;
vector<int> iv;

points.push_back(mypoint(1,2));
points.push_back(mypoint(3,4));
points.push_back(mypoint(5,6));

for_each(points.cbegin(), points.cend(),
    [&iv](const mypoint &pt) {
        iv.push_back(pt.x);
        iv.push_back(pt.y);
    });
于 2013-03-27T15:50:32.467 回答
1

您可以使用 astd::pair<>在其中推送坐标std::make_pair,然后将其推std::pair<>送到向量中,例如:

mypoint a_point;
std::pair<int, int> point = std::make_pair(a_point.x, a_point.y);
vector<std::pair<int, int>> vec.push_back(point).

也许笨重,但在两行中它运行良好并封装了一个点,而不是分离每个点轴的大小并将它们放在一个std::vector.

于 2013-03-27T15:51:12.600 回答
1

正如 reima 已经指出的那样,如果您只想引用现有序列,则强制转换myvector.data()int*(假设sizeof(mypoint) == 2 * sizeof(int)保持)就足够了。但是,如果您明确想要一个展平序列的副本,您最好创建一个像这样的小型实用程序函数:

    template <typename T, typename U>
    std::vector<T> flatten(std::vector<U> const& other) {
        static_assert(std::is_trivially_copyable<U>::value,
                      "source type must be trivially copyable!");
        static_assert(std::is_trivially_copy_constructible<T>::value,
                      "destination type must be trivially copy constructible!");
        static_assert((sizeof(U) / sizeof(T)) * sizeof(T) == sizeof(U),
                      "sizeof(U) must be a multiple of sizeof(T)!");

        return std::vector<T>(reinterpret_cast<T const*>(other.data()),
           reinterpret_cast<T const*>(std::next(other.data(), other.size())));             
    }

    template <typename U>
    std::vector<typename U::value_type> flatten(std::vector<U> const& other) {
         return flatten<typename U::value_type>(other);
    }

减少你的代码

    auto newvector = flatten<int>(myvector);

或者 - 如果你为你配备mypoint struct(符合 STL 的)value_type成员类型 - 甚至

    auto newvector = flatten(myvector);

请注意,这个实用函数只不过是一个经过调整的构造函数,它使用固有的不安全reinterpret_castmypoint指针转换为int指针。为了摆脱伴随使用的安全警告reinterpret_cast,该flatten函数使用了一些static_assert降落伞。因此,最好将所有这些隐藏在一个单独的函数中。尽管如此,它还是使用了许多 C++11 特性auto,例如移动构造、static_assert类型特征,std::next并且vector::data()几乎将您的调用站点代码剥离到最低限度。

此外,这是尽可能高效的,因为 range 构造函数vector只会执行内存分配和调用uninitialized_copy,这可能会归结为memcpy对普通可复制类型的调用。

于 2013-03-28T09:53:38.510 回答