С новым циклом for на основе диапазона мы можем писать такой код, как
for(auto x: Y) {}
Какой IMO является огромным улучшением (например)
for(std::vector<int>::iterator x=Y.begin(); x!=Y.end(); ++x) {}
Можно ли использовать его для перебора двух одновременных циклов, например zip
функции Pythons ? Для тех, кто не знаком с Python, код:
Y1 = [1,2,3]
Y2 = [4,5,6,7]
for x1,x2 in zip(Y1,Y2):
print x1,x2
Выдает как результат (1,4) (2,5) (3,6)
for
можно использовать только одну переменную, поэтому нет. Если вы хотите получить доступ к двум значениям одновременно, вам нужно будет использовать что-то вродеstd::pair
zip()
функцию, которая возвращает кортежи и выполняет итерацию по списку кортежей.for(;;)
можно добиться такого поведения, хотя и долгого, так что вопрос в самом деле: возможно ли для «авто» использовать сразу два объекта?Ответы:
Предупреждение:
boost::zip_iterator
иboost::combine
начиная с Boost 1.63.0 (26 декабря 2016 г.) вызовет неопределенное поведение, если длина входных контейнеров не одинакова (это может привести к сбою или итерации за пределами конца).Начиная с Boost 1.56.0 (7 августа 2014 г.) вы можете использовать
boost::combine
(функция существует в более ранних версиях, но недокументирована):Это напечатает
В более ранних версиях вы могли сами определить диапазон следующим образом:
Использование такое же.
источник
optional
элементами дляТак что я написал этот zip раньше, когда мне было скучно, я решил опубликовать его, потому что он отличается от других тем, что не использует ускорение и больше похож на c ++ stdlib.
Пример использования:
источник
[](int i,int j,float k,float l)
работает? Это лямбда-функция?std::for_each
но вы можете использовать произвольное количество диапазонов, параметры в лямбде зависят от того, сколько итераторов вы даете функции,std :: transform может сделать это тривиально:
Если вторая последовательность короче, моя реализация, похоже, дает инициализированные значения по умолчанию.
источник
b
.Вы можете использовать решение на основе
boost::zip_iterator
. Создайте фальшивый контейнерный класс, поддерживающий ссылки на ваши контейнеры, которые возвращаютсяzip_iterator
из функций-членовbegin
иend
. Теперь ты можешь писатьПример реализации (протестируйте):
Я оставляю вариативную версию как отличное упражнение для читателя.
источник
boost::iterator_range
+boost::zip_iterator
, даже в вариационной версии.boost::zip_iterator
не работает с диапазонами разной длиныСм
<redi/zip.h>
дляzip
функции , которая работает с диапазоном базойfor
и принимает любое количество диапазонов, которые могут быть rvalues или lvalues и может быть разной длиной (итерация остановится в конце самого короткого диапазона).Печать
0 1 2 3 4 5
источник
boost/tuple/tuple_io.hpp
tocout << i;
boost::get<0>(i)
иboost::get<1>(i)
. Я не уверен, почему исходный образец нельзя было адаптировать напрямую, возможно, это связано с тем, что мой код принимает постоянные ссылки на контейнеры.С диапазоном-v3 :
Выход:
источник
Я столкнулся с этим же вопросом независимо, и мне не понравился синтаксис любого из вышеперечисленных. Итак, у меня есть короткий заголовочный файл, который, по сути, делает то же самое, что и boost zip_iterator, но имеет несколько макросов, чтобы сделать синтаксис более удобным для меня:
https://github.com/cshelton/zipfor
Например, вы можете сделать
Главный синтаксический сахар состоит в том, что я могу давать названия элементам из каждого контейнера. Я также включаю «mapfor», который делает то же самое, но для карт (чтобы назвать «.first» и «.second» элемента).
источник
источник
Если вам нравится перегрузка операторов, есть три возможности. Первые два используют
std::pair<>
иstd::tuple<>
, соответственно, в качестве итераторов; третий расширяет это до диапазонаfor
. Обратите внимание, что не всем понравятся эти определения операторов, поэтому лучше хранить их в отдельном пространстве имен и иметьusing namespace
в функциях (а не в файлах!), Где вы хотели бы их использовать.источник
Для библиотеки потоковой обработки C ++, которую я пишу, я искал решение, которое не полагается на сторонние библиотеки и работает с произвольным количеством контейнеров. Я пришел к этому решению. Это похоже на принятое решение, которое использует ускорение (а также приводит к неопределенному поведению, если длины контейнеров не равны)
источник
operator*
forseq::iterator
возвращаетstd::tuple
константные ссылки.Если у вас есть компилятор, совместимый с C ++ 14 (например, gcc5), вы можете использовать
zip
предоставленный вcppitertools
библиотеке Ryan Haining, что выглядит действительно многообещающим:источник
Boost.Iterators
zip_iterator
можно использовать (примеры в документации). Он не будет работать с диапазоном для, но вы можете использоватьstd::for_each
и лямбду.источник
for_each
будет меньше хлопот.std::for_each(make_zip_iterator(make_tuple(Y1.begin(), Y2.begin())), make_zip_iterator(make_tuple(Y1.end(), Y2.end())), [](const tuple<int, int>& t){printf("%d %d\n", get<0>(t), get<1>(t)); });
?Вот простая версия, не требующая буста. Он не будет особенно эффективным, поскольку он создает временные значения и не обобщает контейнеры, кроме списков, но он не имеет зависимостей и решает наиболее распространенный случай архивирования.
Хотя другие версии более гибкие, часто смысл использования оператора списка состоит в том, чтобы сделать простой однострочным. Эта версия имеет то преимущество, что общий случай прост.
источник