4

I'm wondering: is there any possibility to add additional condition to for each? I'm thinking about something like:

int i=0; for(auto &it : list; i++) if(it.ID == 25) return i; 

or

for(auto &it : list, int i=0; i++) if(it.ID == 25) return i; 
3
  • 1
    Why not just use a traditional for loop at this point? Commented Sep 13, 2013 at 5:35
  • 3
    No. Just add it within the body of the loop. Commented Sep 13, 2013 at 5:37
  • boost::zip_iterator together with some sequence glue could do this for you. Something like: for( auto pair : zip(list, sequence(0, infinity)) ) { if( pair.first == 25) return pair.second; } syntax could be created with a bunch of work. Commented Sep 18, 2013 at 14:35

3 Answers 3

6

You can use std::find_if:

const auto position = std::find_if(list.cbegin(), list.cend(), []((decltype(*list.cbegin()) value) { return value.ID == 25; }); return position - list.cbegin(); 

(Updated, now independent of container value_type)

Sign up to request clarification or add additional context in comments.

Comments

1

No it's not possible. You can use the old "normal" for loop for that:

auto iter = std::begin(list) for (int i = 0; iter != std::end(list); ++iter, ++i) { auto& it = *iter; // ... } 

Comments

1

Mandatory Reference: Sean Parent's "Seasoning C++" talk:

goal 1: Avoid raw loops

In cases like these, abstract your algorithm!

This will come up more often, so it's worth making it generic:

#include <algorithm> template <typename C, typename Pred> size_t index_if(C const& c, Pred&& pred) { const auto f(begin(c)), l(end(c)); auto match = std::find_if(f, l, std::forward<Pred>(pred)); return (l==match) ? -1 : std::distance(f, match); } 

Now you can write your query:

int main() { struct X { int ID; }; const std::vector<X> v { {1},{2},{3},{25},{4},{5},{6},{42} }; return index_if(v, [](X const& x) { return x.ID == 25; }); } 

See it Live on Coliru


PS. You might want a value-based version along with the predicate-based one:

template <typename C, typename V/* = typename C::value_type*/> size_t index_of(C const& c, V const v) { const auto f(begin(c)), l(end(c)); auto match = std::find(f, l, v); return (l==match) ? -1 : std::distance(f, match); } 

7 Comments

nice algorithm, but the OP does not compare an object of container::value_type with a constant container::value_type, but only one field. std::find does not work for this
@stefan just spotted it and changed my answer :/
a little late, I watched the video but I don;t think that guy is right that you should blindly replace your loops with functions from the STL. These kind of mantras are dangerous, avoid this, avoid that .... You should always pay attention to the big picture and, maybe, a raw loop in 3 lines is the most performant solution sometimes, specially if you are blindly calling mamooth STL functions that by the way can have raw loops inside.
@rupps "blindly" whatever is never good. Your mantra is "avoid mantras". Also, you suggest that performance was the goal. 99% of the time performance is subordinate to correctness and maintainability. Yes, "STL functions can have raw loops inside". No they cannot: by the very definition, they are no longer raw: You cannot write a loop condition wrong (off-by-one errors? mixed signed/unsigned comparison? name hiding? boundary cases (say std::rotate with middle equal to begin/end) etc), ...
|

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.