15

我想写一些类似于 python zip ( http://docs.python.org/2/library/functions.html ) 的东西。zip 应该接受可变数量的不同类型的向量,并返回一个元组向量,截断为最短输入的长度。

例如

x = [1, 2, 3]
v = ['a', 'b']

我希望输出是一个向量 [ <1, 'a'>, <2, 'b'>]

我如何在 C++11 中做到这一点?

4

3 回答 3

20

急切地做这件事,而且只有复制是很容易的:

#include <vector>
#include <tuple>
#include <algorithm>

template<class... Ts>
std::vector<std::tuple<Ts...>> zip(std::vector<Ts> const&... vs){
    auto lo = std::min({vs.size()...});
    std::vector<std::tuple<Ts...>> v;
    v.reserve(lo);
    for(unsigned i = 0; i < lo; ++i)
        v.emplace_back(vs[i]...);
    return v;
}

活生生的例子。

有了完美的转发并允许移出向量,它变得有点复杂,主要是由于助手:

#include <vector>
#include <tuple>
#include <algorithm>
#include <type_traits>

template<class T>
using Invoke = typename T::type;

template<class T>
using Unqualified = Invoke<std::remove_cv<Invoke<std::remove_reference<T>>>>;

template<class T>
using ValueType = typename Unqualified<T>::value_type;

template<class T>
T const& forward_index(std::vector<T> const& v, unsigned i){
    return v[i];
}

template<class T>
T&& forward_index(std::vector<T>&& v, unsigned i){
    return std::move(v[i]);
}

template<class... Vs>
std::vector<std::tuple<ValueType<Vs>...>> zip(Vs&&... vs){
    auto lo = std::min({vs.size()...});
    std::vector<std::tuple<ValueType<Vs>...>> v;
    v.reserve(lo);
    for(unsigned i = 0; i < lo; ++i)
        v.emplace_back(forward_index(std::forward<Vs>(vs), i)...);
    return v;
}

活生生的例子。

于 2013-06-17T21:59:08.880 回答
5

下面的模板函数可能是一个很好的起点。

template <typename ...Types>
auto zip(const std::vector<Types>&... values)
    -> std::vector<std::tuple<Types...>>
{
    auto size = std::min({ values.size()... });
    std::vector<std::tuple<Types...>> result;
    for (std::size_t i = 0; i != size; ++i) {
        result.emplace_back(values[i]...);
    }
    return result;
}
于 2013-06-17T21:57:33.230 回答
2

这应该做你想要的。它适用于任何范围,而不仅仅是vector.

template <typename Iterator0, typename Iterator1>
std::vector<std::tuple<
    typename Iterator0::value_type,
    typename Iterator1::value_type>>
zip(
    Iterator0 begin0, Iterator0 end0,
    Iterator1 begin1, Iterator1 end1)
{
    std::vector<std::tuple<
        typename Iterator0::value_type,
        typename Iterator1::value_type>> result;
    while (begin0 != end0 && begin1 != end1)
    {
        result.emplace_back(*begin0, *begin1);
        ++begin0;
        ++begin1;
    }
    return result;
}

你这样称呼它。

std::vector<int> x;
std::vector<double> y;
auto xy = zip(x.begin(), x.end(), y.begin(), y.end());

你可以在这里试试

可能可以修改zip为使用可变参数模板,以便您可以将任意数量的范围压缩在一起。

要进一步匹配<algorithm>标头,您可以返回void并取一个输出迭代器,输出将写入该迭代器。

于 2013-06-17T21:54:18.417 回答