user1101674
user1101674

Reputation: 1421

Neatest way to loop over a range of integers

Since C++11 introduced the range-based for loop (range-based for in c++11), what is the neatest way to express looping over a range of integers?

Instead of

for (int i=0; i<n; ++i)

I'd like to write something like

for (int i : range(0,n))

Does the new standard support anything of that kind?

Update: this article describes how to implement a range generator in C++11: Generator in C++

Upvotes: 69

Views: 68099

Answers (6)

Fureeish
Fureeish

Reputation: 13444

With C++20 we will have ranges. If you don't have access to C++20, you can try them out by downloading the lastest stable release from it's author, Eric Niebler, from his github, or go to Wandbox. What you are interested in is ranges::views::iota, which makes this code legal:

#include <range/v3/view/iota.hpp>
#include <iostream>

int main() {
    using namespace ranges;
    
    for (const int i : views::iota(1, 10)) {
        std::cout << i << ' ';
    }
}

What's great about this approach is that views are lazy. This means that even though views::iota represents a range from 1 to 10 exclusive, no more than one int from that range exists at a given time. The elements are generated on demand.

If you do have access to C++20, this version works out of the box:

#include <ranges>
#include <iostream>

int main() {  
    for (const int i : std::views::iota(1, 10)) {
        std::cout << i << ' ';
    }
}

Upvotes: 47

pashchenkoromak
pashchenkoromak

Reputation: 16

Well, I really like the solution, provided here (I'm sorry, it's not translated in English):

#define FOR(I,UPPERBND) for(int I = 0; I<int(UPPERBND); ++I)

The main idea is described in this way: when we talk about simple iteration-indexed-cycles, we do not need to think about it. However, when we use for(;;) construction- there are always three steps: initialization, end condition check, iteration. And this is an overkill for such a simple loop, as just i:[0,n). I liked the idea, that we want to write simple things in a simple way. When you see that FOR(i,N) - you just know, that there are nothing special. When you see the for(;;) construction - you have to be more careful and see all three parts of it. Just an example from that article:

for (int iter=0; iter<nb_iter; iter++) {          // some iterative computation
    for (int c=0; c<mesh.cells.nb(); c++)         // loop through all tetrahedra
        for (int lv0=0; lv0<4; lv0++)             // for every pair of
            for (int lv1 = lv0+1; lv1<4; lv1++)   // vertices in the tet
                for (int d=0; d<3; d++) {         // do stuff for each of 3 dimensions
                    nlRowScaling(weight);
                    nlBegin(NL_ROW);
                    nlCoefficient(mesh.cells.vertex(c, lv0)*3 + d,  1);
                    nlCoefficient(mesh.cells.vertex(c, lv1)*3 + d, -1);
                    nlEnd(NL_ROW);
                }
    [...]
}

become a:

FOR(iter, nb_iter) {
    FOR(c, mesh.cells.nb())
        FOR(lv0, 4)
            for (int lv1 = lv0+1; lv1<4; lv1++)
                FOR(d, 3) {
                    nlRowScaling(weight);
                    nlBegin(NL_ROW);
                    nlCoefficient(mesh.cells.vertex(c, lv0)*3 + d,  1);
                    nlCoefficient(mesh.cells.vertex(c, lv1)*3 + d, -1);
                    nlEnd(NL_ROW);
                }
    [...]
}

And you see, where you should concentrate your attention.

Upvotes: -5

Mike Redrobe
Mike Redrobe

Reputation: 1296

If you don't mind doing the loop in reverse order, you can replace

for (int i=0; i<n; ++i)

with simpler

for (int i=n; i--;)

Upvotes: 4

ixSci
ixSci

Reputation: 13718

While its not provided by C++11, you can write your own view or use the one from boost:

#include <boost/range/irange.hpp>
#include <iostream>

int main(int argc, char **argv)
{
    for (auto i : boost::irange(1, 10))
        std::cout << i << "\n";
}

Moreover, Boost.Range contains a few more interesting ranges which you could find pretty useful combined with the new for loop. For example, you can get a reversed view.

Upvotes: 39

Emilio Garavaglia
Emilio Garavaglia

Reputation: 20769

Depending on what you have to do with the integer, consider the also the <numeric> header, in particular std::iota in conjunction with std::transform and std::fill depending on the cases.

Upvotes: 0

BЈовић
BЈовић

Reputation: 64303

The neatest way is still this:

for (int i=0; i<n; ++i)

I guess you can do this, but I wouldn't call it so neat:

#include <iostream>

int main()
{
  for ( auto i : { 1,2,3,4,5 } )
  {
    std::cout<<i<<std::endl;
  }
}

Upvotes: 43

Related Questions