Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to iterate over two containers sequentially

Tags:

c++

I have two vectors. I want to iterate over all elements of both and do something (say print them out). So I could write something like:

vector<int> vec_a{1, 2, 3}, vec_b{4, 5, 6, 7};

for (auto a : vec_a) {
  cout << a;
}
for (auto b : vec_b) {
  cout << b;
}

This has a lot of duplication. I could do something like:

for (const auto& vec : {vec_a, vec_b}) {
  for (auto elem : vec) {
    cout << elem;
  }
}

But this adds an extra for (which is not too bad but I'm wondering if there is something better. Something along the lines of:

for (auto elem : concat(vec_a, vec_b)) {
  cout << elem;
}

I know I could just concat the vectors (a la Concatenating two std::vectors) but that syntax is even clunkier (especially since I actually have 4 vectors).

I want the output to be:

1 2 3 4 5 6 7

like image 345
Benjy Kessler Avatar asked Oct 15 '20 12:10

Benjy Kessler


People also ask

What is the best way to create a sequential container?

Use std:vector as your default sequential container, especially as an alternative to built-in arrays If you add or remove elements frequently at both the front and back of a container, use std::deque Use a std::list (not std::deque) if you need to insert/remove elements in the middle of the sequence

How to iterate over a set in C++?

This article focuses on discussing all the methods that can be used to iterate over a set in C++. The following methods will be discussed in this article: Iterate over a set using an iterator. Iterate over a set in backward direction using reverse_iterator. Iterate over a set using range-based for loop. Iterate over a set using for_each loop.

How do you iterate over multiple lists in Python?

For better understanding of iteration of multiple lists, we are iterating over 3 lists at a time. zip () : In Python 3, zip returns an iterator. zip () function stops when anyone of the list of all the lists gets exhausted. In simple words, it runs till the smallest of all the lists.

How to iterate over a set using iterator in Python?

Let’s start discussing each of these methods in detail. Iterating over a set using iterator. In this method, an iterator itr is created and initialized using begin () function which will point to the first element, and after every iteration, itr points to the next element in a set and it will continue to iterate until it reaches the end of the set.


Video Answer


2 Answers

A simple solution is to use a helper function:

#include <functional>

template <typename Func, typename... Containers>
void for_all(Func&& func, Containers&&... containers) {
    auto iteration_func = [&](auto&& container) {
        for (auto&& elem : std::forward<decltype(container)>(container)) {
            std::invoke(func, std::forward<decltype(elem)>(elem));
        }
    };

    (iteration_func(std::forward<Containers>(containers)), ...);
}

Here, we use a fold expression with an immediately invoked lambda to simulate a loop over the variadic template arguments, where each of them is looped over and the provided function object is invoked on its elements.

The use of forwarding references and invocations to std::forward preserve the value categories of arguments and elements, for compatibility with rvalue ranges (e.g., move_view from the range-v3 library). std::invoke generalizes the notion of function objects to pointers to members, which can be useful in certain cases.

Example:

int main() {
    std::vector<int> vec_a{1, 2, 3};
    std::vector<int> vec_b{4, 5, 6, 7};
    
    for_all([](int n) {
        std::cout << n << ' ';
    }, vec_a, vec_b);
    
    std::cout << '\n';
}

(wandbox)

Different container types can be mixed:

for_all([](const auto& n) {
    std::cout << n << ' ';
}, std::vector{1, 2, 3}, std::list{"foo", "bar"});
like image 54
L. F. Avatar answered Sep 27 '22 21:09

L. F.


There is nice range library which works with C++14 and in large part will become part of C++20. In this library there is ranges::views::concat which does exactly what you need in nice clean way:

#include <iostream>
#include <ranges>
#include <vector>
#include <array>
#include <functional>
#include <range/v3/view/concat.hpp>

int main()
{
    using ranges::views::concat;
    
    auto a = std::vector<int>{ 1, 2, 6, 7 };
    auto b = std::array<int , 2>{ 1, 3 };
    auto c = { -1, -4, 7, 8, 9, 11};

    for (auto x : concat(a, b)) {
        std::cout << x << ", ";
    }
    std::cout << "\n--\n";

    for (auto x : concat(c, a, b)) {
        std::cout << x << ", ";
    }

    return 0;
}

https://godbolt.org/z/Waf3Ma

Sadly concat is not available in C++20 (can't find it in documentation and gcc do not support it).

like image 43
Marek R Avatar answered Sep 27 '22 21:09

Marek R