С++ 11 вариационных шаблонов: возвращает кортеж из списка переменных векторов
Я хочу написать что-то похожее на python zip (http://docs.python.org/2/library/functions.html).
zip должен принимать переменное число векторов разных типов и возвращает вектор
кортежей, усеченных до длины кратчайшего ввода.
например.
x = [1, 2, 3]
v = ['a', 'b']
Я хочу, чтобы результат был вектором
[ <1, 'a'>, <2, 'b'>]
Как это сделать в С++ 11?
Ответы
Ответ 1
Выполнение этого с нетерпением и только с копированием довольно просто:
#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;
}
Пример в реальном времени.
Ответ 2
Следующая функция шаблона может быть хорошей отправной точкой.
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;
}
Ответ 3
Это должно делать то, что вы хотите. Он работает для любого диапазона, а не только 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
и вместо этого взять выходной итератор, на который будет записываться вывод.