Implementation of Python-like enumerate() Function in C++
Introduction
In the previous article, you created a function that has similar functionality to Python’s zip()
function. This allows you to handle multiple containers at once in a single range-based for loop.
However, with the range-based for loop, you don’t have access to the current element’s index. To achieve that, you would need to write it in a way that does not use the range-based for loop, as shown below:
std::vector<int> a = [1, 2, 3];
for(size_t i = 0; i < a.size(); i++){
std::cout << a[i] << std::endl;
}
It is true that it can sometimes feel inconvenient to not take advantage of iterators when they are available.
When working with languages like Python, the presence of the enumerate()
function, which allows for handling indices along with elements as shown below, can be quite handy.
a = [1, 2, 3]
for i, elem in enumerate(a):
print(f"{i}: {elem}")
Using C++17’s structured bindings, it seems you can achieve a similar functionality. Therefore, in this article, I attempted to create an Enumerator
class that uses tuples to handle indices and elements together, along with an Enumerate()
function that returns instances of the Enumerator
class.
Implementation and Usage
Implementation
Please refer to the source code uploaded on GitHub.
To apply range-based for loops similarly to the Zipper
class, begin()
and end()
are implemented as member functions of the container, along with the implementation of iterators. When using the dereference operator *
of the iterator, it returns a tuple of index and container element. By utilizing GetReference<>
created in this article, it also supports arrays.
In the code uploaded to GitHub, a specialized Enumerator
class is implemented to handle the Zipper
class created in the previous article. In this class, an object of the Zipper
class is stored as a member variable (not as a reference) to enable receiving right-value references in Enumerate(Zipper &&)
.
Usage
Here is an example of its usage. Let’s assume that zipper.h
and enumerator.h
are in the same directory. (zipper.h
is included in enumerator.h
)
#include <iostream>
#include <list>
#include <map>
#include <string>
#include <vector>
#include "enumerator.h"
int main()
{
std::vector<int> a = {1, 2, 3};
std::list<std::string> b = {"a", "b", "c"};
std::map<int, std::string> c = {{0, "abc"}, {1, "def"}, {2, "ghi"}};
for (auto [i, s, t, u] : Enumerate(Zip(a, b, c))) {
std::cout << "[" << i << "] " << s << " " << t << " " << u.first << " " << u.second << std::endl;
}
return 0;
}
Conclusion
I tried creating a Python-like Enumerate()
function using tuples. It allows you to combine index and element in one for loop. By combining it with the Zip()
function, you can also handle multiple containers’ elements and indexes together.
Note that in C++23, the std::views::enumerate()
function is standardized in <ranges>
as well. It’s advisable to use that if you’re in an environment that supports C++23.
std::vector<int> a = {1, 2, 3};
std::list<std::string> b = {"aaa", "bbb", "ccc"};
for(auto & [i, p, q]: std::views::enumerate(std::views::zip(a, b))) {
std::println("{}: {}, {}", i, p, q);
}
Discussion
New Comments
No comments yet. Be the first one!