C ++ 11 предоставляет несколько способов перебора контейнеров. Например:
Цикл на основе диапазона
for(auto c : container) fun(c)
std :: for_each
for_each(container.begin(),container.end(),fun)
Однако каков рекомендуемый способ перебора двух (или более) контейнеров одинакового размера для выполнения чего-то вроде:
for(unsigned i = 0; i < containerA.size(); ++i) {
containerA[i] = containerB[i];
}
c++
c++11
iterator
containers
мемы
источник
источник
transform
присутствия#include <algorithm>
?containerA = containerB;
вместо цикла.Ответы:
Скорее поздно на вечеринку. Но: я бы перебирал индексы. Но не с классическим
for
циклом, а сfor
циклом на основе диапазона по индексам:indices
- простая функция-оболочка, которая возвращает (лениво вычисленный) диапазон для индексов. Поскольку реализация - хотя и простая - слишком длинная, чтобы размещать ее здесь, вы можете найти реализацию на GitHub .Этот код так же эффективен, как использование ручного классического
for
цикла.Если этот шаблон часто встречается в ваших данных, рассмотрите возможность использования другого шаблона, который
zip
состоит из двух последовательностей и создает диапазон кортежей, соответствующих парным элементам:Реализация
zip
оставлена в качестве упражнения для читателя, но легко следует из реализацииindices
.(До C ++ 17 вам приходилось писать следующее :)
источник
boost::counting_range(size_t(0), containerA.size())
indices
реализации дает вывод компилятора, который идентичен использованию ручныхfor
циклов. Никаких накладных расходов нет.Для вашего конкретного примера просто используйте
В более общем случае вы можете использовать Boost.Iterator
zip_iterator
с небольшой функцией, чтобы его можно было использовать в циклах for на основе диапазона. В большинстве случаев это сработает:Живой пример.
Однако для полной универсальности вам, вероятно, понадобится что-то большее, например это , который будет работать правильно для массивов и определяемые пользователем типы , которые не имеют члена
begin()
/end()
но у естьbegin
/end
функции в их имен. Кроме того, это позволит пользователю специально получитьconst
доступ черезzip_c...
функции.И если вы, как и я, сторонник хороших сообщений об ошибках, то вам, вероятно, понадобится это , которое проверяет, были ли переданы какие-либо временные контейнеры какой-либо из
zip_...
функций, и выводит красивое сообщение об ошибке, если да.источник
auto
работает точно так же, как параметр шаблона, иT&&
в шаблоне есть универсальная ссылка, как объяснено в первой ссылке, поэтомуauto&& v = 42
будет выводиться как,int&&
аauto&& w = v;
затем будет выводиться какint&
. Это позволяет вам сопоставлять lvalue, а также rvalue, и позволять изменять оба значения без создания копии.zip_range
.Интересно, почему об этом никто не упомянул:
PS: если размеры контейнера не совпадают, вам придется поместить код внутри операторов if.
источник
Есть много способов делать определенные вещи с несколькими контейнерами, как указано в
algorithm
заголовке. Например, в приведенном вами примере вы можете использоватьstd::copy
вместо явного цикла for.С другой стороны, нет какого-либо встроенного способа для общей итерации нескольких контейнеров, кроме обычного цикла for. Это не удивительно, потому что есть много способов итерации. Подумайте об этом: вы можете перебирать один контейнер за один шаг, один контейнер за другой; или через один контейнер, пока он не дойдет до конца, затем начните вставку, пока вы проходите до конца другого контейнера; или один шаг первого контейнера каждый раз, когда вы полностью проходите через другой контейнер, а затем начинаете заново; или какой-то другой узор; или более двух контейнеров одновременно; и т.д ...
Однако, если вы хотите создать свою собственную функцию стиля "for_each", которая выполняет итерацию по двум контейнерам только до длины самого короткого, вы можете сделать что-то вроде этого:
Очевидно, вы можете создать любую стратегию итераций подобным образом.
Конечно, вы можете возразить, что просто выполнить внутренний цикл for напрямую, чем написать такую пользовательскую функцию ... и вы будете правы, если собираетесь проделать это только один или два раза. Но приятно то, что его можно использовать повторно. знак равно
источник
for (Container1::iterator i1 = c1.begin(), Container2::iterator i2 = c2.begin(); (i1 != end1) && (i2 != end2); ++it1, ++i2)
но компилятор орет. Может ли кто-нибудь объяснить, почему это неверно?for (int x = 0, y = 0; ...
работает, аfor (int x = 0, double y = 0; ...)
нет.typename...
В случае, когда вам нужно выполнять итерацию одновременно только по 2 контейнерам, в библиотеке диапазонов ускорения есть расширенная версия стандартного алгоритма for_each, например:
Когда вам нужно обрабатывать более 2 контейнеров в одном алгоритме, вам нужно поиграть с zip.
источник
другое решение может заключаться в захвате ссылки на итератор другого контейнера в лямбда-выражении и использовании для этого оператора пост-инкремента. например, простая копия будет:
внутри лямбды вы можете делать все, что угодно,
ita
а затем увеличивать его. Это легко распространяется на случай нескольких контейнеров.источник
Библиотека диапазонов предоставляет эту и другие очень полезные функции. В следующем примере используется Boost.Range . Rangev3 Эрика Ниблера должен быть хорошей альтернативой.
C ++ 17 сделает это еще лучше с помощью структурированных привязок:
источник
delme.cxx:15:25: error: no match for 'operator=' (operand types are 'std::tuple<int&, char&>' and 'const boost::tuples::cons<const int&, boost::tuples::cons<const char&, boost::tuples::null_type> >') std::tie(ti,tc) = i;
^19.13.26132.0
версии MSVC и Windows SDK10.0.16299.0
):error C2679: binary '<<': no operator found which takes a right-hand operand of type 'const boost::tuples::cons<const char &,boost::fusion::detail::build_tuple_cons<boost::fusion::single_view_iterator<Sequence,boost::mpl::int_<1>>,Last,true>::type>' (or there is no acceptable conversion)
boost::combine
: stackoverflow.com/q/55585723/8414561Я тоже немного опоздал; но вы можете использовать это (вариативная функция в стиле C):
или это (с использованием пакета параметров функции):
или это (с использованием списка инициализаторов, заключенного в фигурные скобки):
или вы можете объединить векторы, как здесь: Как лучше всего объединить два вектора? а затем перебрать большой вектор.
источник
Вот один вариант
Пример использования
источник