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

46,410

Solution 1

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]);

Solution 2

Maybe it's enough to have a variable i?

unsigned i = 0;
for ( char c : str ) {
  if ( c == 'b' ) vector.push_back(i);
  ++i;
}

That way you don't have to change the range-based loop.

Solution 3

The range loop will not give you the index. It is meant to abstract away such concepts, and just let you iterate through the collection.

Solution 4

What you are describing is known as an 'each with index' operation in other languages. Doing some quick googling, it seems that other than the 'old-school for loop', you have some rather complicated solutions involving C++0x lambas or possibly some Boost provided gems.

EDIT: As an example, see this question

Solution 5

In C++ 20, I use initializer like this:

for(unsigned short i = 0; string item : nilai){
   cout << i << "." << "address " << &item << " -> " << item << endl;
   i++;
}

So, your case will be like:

for (unsigned short i = 0; char c : str ) {
  if ( c == 'b' ) vector.push_back(i);
  ++i;
}

I don't know what 'vector' mean in your case, and what is push_back(). Don't forget to add -std=c++20 (I just use g++ for compiling, so i don't know much about other compiler). You can also start the 'i' value from 1 if you want to. I think it's elegant enough

Share:
46,410
Shane Hsu
Author by

Shane Hsu

Interested in OS X/iOS Development, algorithmic, and competitive programming.

Updated on July 09, 2022

Comments

  • Shane Hsu
    Shane Hsu almost 2 years

    My code is as follows:

    std::cin >> str;
    for ( char c : str )
        if ( c == 'b' ) vector.push_back(i) //while i is the index of c in str
    

    Is this doable? Or I will have to go with the old-school for loop?

  • Shane Hsu
    Shane Hsu over 11 years
    It's a solution, but it's not elegant. Also, I think it will be pointless as it's implementing traditional for loop in a range-based one.
  • Daniel Frey
    Daniel Frey over 11 years
    Maybe it's not elegant, but it's the baseline wrt complexity, readability, overhead, etc. for all other upcoming solutions/work-arounds.
  • Shane Hsu
    Shane Hsu over 11 years
    It sure seems complicated, but it's definitely worth learning! Thank! I will look into it.
  • Shane Hsu
    Shane Hsu over 11 years
    Sure. But I really think there should be a constant index in C++ Range-Based for loop.
  • Daniel Frey
    Daniel Frey over 11 years
    You asked about the current language status, where something like index does not exist. Whether and how the language could be extended is a different question and does not belong here.
  • Shane Hsu
    Shane Hsu over 11 years
    Nice! I was thinking that vectors can use something like it - vector.begin(), and you solved my problem! Thanks!
  • mskfisher
    mskfisher over 9 years
    This does not answer the question. The OP wanted the numeric index of the instances of 'b', not the instances themselves.
  • gr4nt3d
    gr4nt3d over 8 years
    Thanks! I got &it - &vector[0] to compile. But is there a nice way such as @ShaneHsu 's comment? I figured out, I had to use &it - vector.begin() using iterators such as const initializer_list<double>& it. However, in a loop such as for(const pair<double, int>& it : vector_of_pairs) this yields an error: no match for ‘operator-’ (operand types are ‘const pair<double, int>*’ and vector<pair<double, int> >::const_iterator . How can I get the address of the iterator ? (Note that the former is in a ctor, whereas the latter is in a const method)
  • Tomasz Gandor
    Tomasz Gandor over 7 years
    One problem with this - the i variable is scoped outside the loop. In case of the traditional for, there is a place where you can declare extra variables, when they are all of the same type (as your main 'loop variable').
  • Steven Lu
    Steven Lu over 6 years
    Note if the underlying storage changes into no longer a vector type, it will break. Likely your integer based semantics would also then break... so this isnt a strong point against doing this. But it does feel like you'd be strengthening your commitment to contiguous storage by doing this.
  • Steven Lu
    Steven Lu over 6 years
    @gr4nt3d your question appears to be about how you cannot obtain an ordering out of an iterator for an associative type, which (say it's a hashtable) pretty much has no ordering, you can only do stuff like check its equality to container.end(), or fetch the next one, etc. See stackoverflow.com/a/43680932/340947
  • gr4nt3d
    gr4nt3d about 6 years
    @StevenLu, I don't get your point; I was referring to plain std::vector (at least telling from the comment, as it's been quite some time since then). As such it would have the ordering that I need, but apparently the expression &it - vector_of_pairs.begin()did not work even though I'd expect the pointer arithmetic to work, as it is contiguously stored. However, I cannot recall the exact case anymore.
  • Steven Lu
    Steven Lu about 6 years
    The difference seems to be between getting the address of the first element of the vector Vs. getting the begin() iterator. I’m not too sure on why or what exactly the limitations are but direct arithmetic on iterators seems to not work
  • zeeMonkeez
    zeeMonkeez over 5 years
    Note that C++20 will allow declaration of i in the for statement: open-std.org/jtc1/sc22/wg21/docs/papers/2017/p0614r1.html . @TomaszGandor for that, you'd encapsulate the for loop with the declaration of I in braces.