How to Find the Index of Current Object in Range-Based For Loop

Get index of current element in C++ range-based for-loop

Assuming str is a std::string or other object with contiguous storage:

std::cin >> str;
for (char& c : str)
if (c == 'b') v.push_back(&c - &str[0]);

Access index of current element in range-for loop c++20

After looking into defining a view interface, I decided to use range-v3.

There are several things missing from std::ranges https://stackoverflow.com/a/68172842/11998382, and until they are added in future standards, it is sensible to use range-v3 rather than repeatedly attempting non-trivial implementations yourself.

Sample Image

Can I get the index of an item from within a range based for loop?

I came up with a solution — or rather an experimental solution. Here is how you will end up using it:

for(auto item : make_indexable(v))
{
//std::get<0>(item) is the index
//std::get<1>(item) is the object
}

And here goes the minimal implementation (it is just to demonstrate the basic idea):

#include <tuple>
#include <functional>

template<typename C>
struct indexed_container
{
struct indexed_iterator
{
typedef typename C::value_type value_type;
typedef std::tuple<size_t, std::reference_wrapper<value_type>> tuple_type;

typename C::iterator _it;
size_t _index;

indexed_iterator(typename C::iterator it) : _it(it), _index(0) {}

indexed_iterator& operator++()
{
++_it;
++_index;
return *this;
}
bool operator == (indexed_iterator const & other)
{
return _it == other._it;
}
bool operator != (indexed_iterator const & other)
{
return _it != other._it;
}
tuple_type operator*()
{
return std::make_tuple(_index, std::ref(*_it));
}
};

indexed_container(C & c) : _c(c) {}

indexed_iterator begin()
{
return indexed_iterator(_c.begin());
}
indexed_iterator end()
{
return indexed_iterator(_c.end());
}
private:
C & _c;
};

template<typename C>
auto make_indexable(C & c) -> indexed_container<C>
{
return indexed_container<C>(c);
}

Test code:

#include <iostream>
#include <vector>

int main()
{
std::vector<int> v{1,2,3};
for(auto item : make_indexable(v))
{
std::cout << std::get<0>(item) << " => " << std::get<1>(item) << std::endl;

std::get<1>(item) *= 10; //modify value!
}
std::cout << "\nModified\n";
for(auto item : make_indexable(v))
{
std::cout << std::get<0>(item) << " => " << std::get<1>(item) << std::endl;
}
}

Output:

0 => 1
1 => 2
2 => 3

Modified
0 => 10
1 => 20
2 => 30

Online demo

Note that this solution is not perfect, as it will not work with temporaries and const containers (and containers of const objects). Also, right now the underlying object will be returned as reference even if you write auto item as opposed to auto & item (in fact, you cannot write auto &item). But I think these issues can be fixed with a bit more effort and careful design. After all, it is just a demonstration of the basic idea.

Accessing the index in 'for' loops

Use the built-in function enumerate():

for idx, x in enumerate(xs):
print(idx, x)

It is non-pythonic to manually index via for i in range(len(xs)): x = xs[i] or manually manage an additional state variable.

Check out PEP 279 for more.

Access index in range-for loop

You can't. The index is a specific notion to a vector, and not a generic property of a collection. The range-based loop on the other hand is a generic mechanism for iterating over every element of any collection.

If you do want to use the details of your particular container implementation, just use an ordinary loop:

for (std::size_t i = 0, e = v.size(); i != e; ++i) { /* ... */ }

To repeat the point: Range-based loops are for manipulating each element of any collection, where the collection itself doesn't matter, and the container is never mentioned inside the loop body. It's just another tool in your toolbox, and you're not forced to use it for absolutely everything. By contrast, if you either want to mutate the collection (e.g. remove or shuffle elements), or use specific information about the structure of the collection, use an ordinary loop.

How do you get the index of the current iteration of a foreach loop?

The foreach is for iterating over collections that implement IEnumerable. It does this by calling GetEnumerator on the collection, which will return an Enumerator.

This Enumerator has a method and a property:

  • MoveNext()
  • Current

Current returns the object that Enumerator is currently on, MoveNext updates Current to the next object.

The concept of an index is foreign to the concept of enumeration, and cannot be done.

Because of that, most collections are able to be traversed using an indexer and the for loop construct.

I greatly prefer using a for loop in this situation compared to tracking the index with a local variable.

Java, How do I get current index/key in for each loop

You can't, you either need to keep the index separately:

int index = 0;
for(Element song : question) {
System.out.println("Current index is: " + (index++));
}

or use a normal for loop:

for(int i = 0; i < question.length; i++) {
System.out.println("Current index is: " + i);
}

The reason is you can use the condensed for syntax to loop over any Iterable, and it's not guaranteed that the values actually have an "index"



Related Topics



Leave a reply



Submit