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.
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
How to Output Coloured Text to a Linux Terminal
What's a Proper Way of Type-Punning a Float to an Int and Vice-Versa
How Could Pairing New[] With Delete Possibly Lead to Memory Leak Only
What Does It Mean to "Odr-Use" Something
Why Do We Need Extern "C"{ #Include ≪Foo.H≫ } in C++
What Does It Mean to Have an Undefined Reference to a Static Member
When Are Static C++ Class Members Initialized
Best C++ Code Formatter/Beautifier
Catch Exception by Pointer in C++
Return Statement VS Exit() in Main()
Getting Size of Array from Pointer C++
Why Use Std::Bind Over Lambdas in C++14
Elegant Solution to Duplicate, Const and Non-Const, Getters
Serializing a Class Which Contains a Std::String