76

How can I do the equivalent of the following using C++/STL? I want to fill a std::vector with a range of values [min, max).

# Python
>>> x = range(0, 10)
>>> x
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

I suppose I could use std::generate_n and provide a functor to generate the sequence, but I was wondering if there is a more succinct way of doing this using STL?

M-V
  • 5,167
  • 7
  • 52
  • 55
  • 9
    [std::iota](http://en.cppreference.com/w/cpp/algorithm/iota). – Jerry Coffin Oct 31 '12 at 06:17
  • Note that in Python2, range returns a real list. In Python3 `range` works more like `xrange` from Python2 and returns an iterable range object. `range` also takes a third parameter which is the step or stride size. – John La Rooy Oct 31 '12 at 06:29
  • I'd like to point this out: Look how high of a chance you have of finding this in a Google search based on its title. That, combined with a clear, concise question that includes shown effort, definitely earns a +1 from me. – chris Oct 31 '12 at 06:35
  • I know about range/xrange - haven't started using Python 3 though. Thanks. – M-V Oct 31 '12 at 06:35
  • 1
    See also: http://stackoverflow.com/q/1977339/485561 – Mankarse Oct 31 '12 at 06:45

11 Answers11

89

In C++11, there's std::iota:

#include <vector>
#include <numeric> //std::iota

int main() {
    std::vector<int> x(10);
    std::iota(std::begin(x), std::end(x), 0); //0 is the starting number
}

C++20 introduced a lazy version (just like Python) as part of the ranges library:

#include <iostream>
#include <ranges>

namespace views = std::views;

int main() {
    for (int x : views::iota(0, 10)) {
        std::cout << x << ' '; // 0 1 2 3 4 5 6 7 8 9
    }
}
chris
  • 60,560
  • 13
  • 143
  • 205
  • 5
    What does *iota* stand for? – Felix Dombek Apr 30 '13 at 10:45
  • 4
    @FelixDombek, take a look at [this question](http://stackoverflow.com/questions/9244879/what-does-iota-of-stdiota-stand-for) – unkulunkulu Apr 30 '13 at 10:50
  • 24
    It's not quite the same. iota fills an existing container, while a range is in itself iteratable but doesn't actually _contain_ the values. A Python range can be made on a few billion items without problems, but don't try that with iota. You'd actually have to create a container with enough elements for that. – André May 13 '15 at 13:33
  • 2
    @André, I agree, and Eric Niebler is doing some great work on this. His `view::iota` (IIRC) should act very similar to Python, being infinite and lazy. – chris May 13 '15 at 13:54
  • 5
    `std::iota` can be used by including `#include` – Lxrd-AJ Aug 26 '18 at 22:13
  • iota is good, but if you need 1M long range, it may take up to 1M * sizeof(T) bytes of memory. – Stepan Dyatkovskiy Sep 26 '19 at 16:52
  • @StepanDyatkovskiy, See my previous comment. C++20 will have such a tool. – chris Sep 26 '19 at 18:49
  • iota Sound likes the iota primitive in APL – zoomlogo Jan 18 '22 at 14:52
  • Why use std::begin(x) rather than x.begin()? – yairchu May 02 '22 at 11:31
  • 1
    @yairchu, If you know the type (as in this example), there's no difference. The primary benefit of `std::begin` is that it works with arrays on top of everywhere `x.begin()` works. Now with C++20, `std::ranges::begin` covers a little bit more, but you're still free to use the more specific version in non-generic code. – chris May 02 '22 at 18:34
24

There is boost::irange:

std::vector<int> x;
boost::push_back(x, boost::irange(0, 10));
Mankarse
  • 39,818
  • 11
  • 97
  • 141
7

I ended up writing some utility functions to do this. You can use them as follows:

auto x = range(10); // [0, ..., 9]
auto y = range(2, 20); // [2, ..., 19]
auto z = range(10, 2, -2); // [10, 8, 6, 4]

The code:

#include <vector>
#include <stdexcept>

template <typename IntType>
std::vector<IntType> range(IntType start, IntType stop, IntType step)
{
  if (step == IntType(0))
  {
    throw std::invalid_argument("step for range must be non-zero");
  }

  std::vector<IntType> result;
  IntType i = start;
  while ((step > 0) ? (i < stop) : (i > stop))
  {
    result.push_back(i);
    i += step;
  }

  return result;
}

template <typename IntType>
std::vector<IntType> range(IntType start, IntType stop)
{
  return range(start, stop, IntType(1));
}

template <typename IntType>
std::vector<IntType> range(IntType stop)
{
  return range(IntType(0), stop, IntType(1));
}
Claudiu
  • 224,032
  • 165
  • 485
  • 680
  • 1
    Plus 1, but you should also have your range function check that your are not stepping away from stop ... – Fantastic Mr Fox Jun 11 '15 at 15:11
  • 1
    @Ben: I think that already works. `range(5, 10, -1)` [gives you an empty list](https://ideone.com/Z56Mxb). – Claudiu Jun 11 '15 at 15:21
  • I used this for a while as an easy way to get an increment variable for foreach loops before realizing this is very slow for that purpose. boost::irange is much faster. – aquirdturtle May 20 '18 at 02:27
  • Would calling `result.reserve((stop - start)/step)` before going through the loop increase the performance? – Anakhand Apr 11 '19 at 17:42
6

I've been using this library for this exact purpose for years:

https://github.com/klmr/cpp11-range

Works very well and the proxies are optimized out.

for (auto i : range(1, 5))
    cout << i << "\n";

for (auto u : range(0u))
    if (u == 3u) 
        break;
    else         
        cout << u << "\n";

for (auto c : range('a', 'd'))
    cout << c << "\n";

for (auto i : range(100).step(-3))
    if (i < 90) 
        break;
    else        
        cout << i << "\n";

for (auto i : indices({"foo", "bar"}))
    cout << i << '\n';
Aiden Koss
  • 121
  • 1
  • 4
3

There is boost::irange, but it does not provide floating point, negative steps and can not directly initialize stl containers.

There is also numeric_range in my RO library

In RO, to initialize a vector:

vector<int> V=range(10);

Cut-n-paste example from doc page (scc - c++ snippet evaluator):

// [0,N)  open-ended range. Only range from 1-arg  range() is open-ended.
scc 'range(5)'
{0, 1, 2, 3, 4}

// [0,N]  closed range
scc 'range(1,5)'
{1, 2, 3, 4, 5}

// floating point 
scc 'range(1,5,0.5)'
{1, 1.5, 2, 2.5, 3, 3.5, 4, 4.5, 5}

// negative step
scc 'range(10,0,-1.5)'
{10, 8.5, 7, 5.5, 4, 2.5, 1}

// any arithmetic type
scc "range('a','z')"
a b c d e f g h i j k l m n o p q r s t u v w x y z

// no need for verbose iota. (vint - vector<int>)
scc 'vint V = range(5);   V' 
{0, 1, 2, 3, 4}

// is lazy
scc 'auto NR = range(1,999999999999999999l);  *find(NR.begin(), NR.end(), 5)'
5

//  Classic pipe. Alogorithms are from std:: 
scc 'vint{3,1,2,3} | sort | unique | reverse'
{3, 2, 1}

//  Assign 42 to 2..5
scc 'vint V=range(0,9);   range(V/2, V/5) = 42;  V'
{0, 1, 42, 42, 42, 5, 6, 7, 8, 9}

//  Find (brute force algorithm) maximum of  `cos(x)` in interval: `8 < x < 9`:
scc 'range(8, 9, 0.01) * cos  || max'
-0.1455

//  Integrate sin(x) from 0 to pi
scc 'auto d=0.001;  (range(0,pi,d) * sin || add) * d'
2

//  Total length of strings in vector of strings
scc 'vstr V{"aaa", "bb", "cccc"};  V * size ||  add'
9

//  Assign to c-string, then append `"XYZ"` and then remove `"bc"` substring :
scc 'char s[99];  range(s) = "abc";  (range(s) << "XYZ") - "bc"'
aXYZ


// Hide phone number:
scc "str S=\"John Q Public  (650)1234567\";  S|isdigit='X';  S"
John Q Public  (XXX)XXXXXXX
Leonid Volnitsky
  • 8,854
  • 5
  • 38
  • 53
3

For those who can't use C++11 or libraries:

vector<int> x(10,0); // 0 is the starting number, 10 is the range size
transform(x.begin(),x.end(),++x.begin(),bind2nd(plus<int>(),1)); // 1 is the increment
Giancarlo Sportelli
  • 1,219
  • 1
  • 17
  • 20
  • `++x.begin()` may be ill-formed(attempt to increment rvalue) if `x.begin()` happens to be a primitive type. The transform also attempts to write to memory one past the end of the vector. – Weijun Zhou Aug 16 '23 at 12:23
2

A range() function similar to below will help:

#include <algorithm>
#include <iostream>
#include <numeric>
#include <vector>
using namespace std;

// define range function (only once)
template <typename T>
vector <T> range(T N1, T N2) {
    vector<T> numbers(N2-N1);
    iota(numbers.begin(), numbers.end(), N1);
    return numbers;
}


vector <int> arr = range(0, 10);
vector <int> arr2 = range(5, 8);

for (auto n : arr) { cout << n << " "; }    cout << endl;
// output:    0 1 2 3 4 5 6 7 8 9

for (auto n : arr2) { cout << n << " "; }   cout << endl;
// output:    5 6 7
Manohar Reddy Poreddy
  • 25,399
  • 9
  • 157
  • 140
1

I don't know of a way to do it like in python but another alternative is obviously to for loop through it:

for (int i = range1; i < range2; ++i) {
    x.push_back(i);
}

chris's answer is better though if you have c++11

Fantastic Mr Fox
  • 32,495
  • 27
  • 95
  • 175
1

If you can't use C++11, you can use std::partial_sum to generate numbers from 1 to 10. And if you need numbers from 0 to 9, you can then subtract 1 using transform:

std::vector<int> my_data( 10, 1 );
std::partial_sum( my_data.begin(), my_data.end(), my_data.begin() );
std::transform(my_data.begin(), my_data.end(), my_data.begin(), bind2nd(std::minus<int>(), 1));
GingerPlusPlus
  • 5,336
  • 1
  • 29
  • 52
  • -1, please format the code correctly (add 4 spaces before each line containing code to turn on monospace font and syntax highlighting) – GingerPlusPlus Sep 28 '14 at 19:25
1

Some time ago I wrote the following _range class, which behaves like Python range (put it to the "range.h"):

#pragma once
#include <vector>
#include <cassert>

template < typename T = size_t >
class _range 
{
        const T kFrom, kEnd, kStep;

    public:

        ///////////////////////////////////////////////////////////
        // Constructor 
        ///////////////////////////////////////////////////////////
        //
        // INPUT:
        //      from - Starting number of the sequence.
        //      end - Generate numbers up to, but not including this number.
        //      step -  Difference between each number in the sequence.     
        //
        // REMARKS:
        //      Parameters must be all positive or all negative
        //
        _range( const T from, const T end, const T step = 1 ) 
            : kFrom( from ), kEnd( end ), kStep( step ) 
        {
            assert( kStep != 0 );
            assert( ( kFrom >= 0 && kEnd > 0 && kStep > 0 ) || ( kFrom < 0 && kEnd < 0 && kStep < 0 ) );
        }

        // Default from==0, step==1
        _range( const T end ) 
            : kFrom( 0 ), kEnd( end ), kStep( 1 ) 
        {
            assert( kEnd > 0 );
        }

    public:

        class _range_iter 
        {
            T fVal;
            const T kStep;
        public:
            _range_iter( const T v, const T step ) : fVal( v ), kStep( step ) {}
            operator T  () const            { return fVal; }
            operator const T & ()           { return fVal; }
            const T operator * () const     { return fVal; }
            const _range_iter & operator ++ ()  { fVal += kStep; return * this; }


            bool operator == ( const _range_iter & ri ) const
            {
                return ! operator != ( ri );
            }

            bool operator != ( const _range_iter & ri ) const
            {   
                // This is a tricky part - when working with iterators
                // it checks only once for != which must be a hit to stop;
                // However, this does not work if increasing kStart by N times kSteps skips over kEnd
                return fVal < 0 ? fVal > ri.fVal : fVal < ri.fVal;  
            }                                               
        };                                                  

        const _range_iter begin()   { return _range_iter( kFrom, kStep ); }
        const _range_iter end()     { return _range_iter( kEnd, kStep ); }

    public:

        // Conversion to any vector< T >
        operator std::vector< T > ( void ) 
        {
            std::vector< T > retRange;
            for( T i = kFrom; i < kEnd; i += kStep )
                retRange.push_back( i );
            return retRange;    // use move semantics here
        }
};


// A helper to use pure range meaning _range< size_t >
typedef _range<>    range;

And some test code looks like the following one:

#include "range.h" 
#include <iterator>
#include <fstream>

using namespace std;

void RangeTest( void )
{
    ofstream ostr( "RangeTest.txt" );
    if( ostr.is_open() == false )
        return;

    // 1:
    ostr << "1st test:" << endl;

    vector< float > v = _range< float >( 256 );
    copy( v.begin(), v.end(), ostream_iterator< float >( ostr, ", " ) );

    // 2:
    ostr << endl << "2nd test:" << endl;

    vector< size_t >    v_size_t( range( 0, 100, 13 ) );
    for( auto a : v_size_t )
        ostr << a << ", ";

    // 3:
    ostr << endl << "3rd test:" << endl;

    auto vvv = range( 123 );    // 0..122 inclusive, with step 1
    for( auto a : vvv )
        ostr << a << ", ";

    // 4:
    ostr << endl << "4th test:" << endl;

    // Can be used in the nested loops as well
    for( auto i : _range< float >( 0, 256, 16.5 ) ) 
    {
        for( auto j : _range< int >( -2, -16, -3 ) ) 
        {
            ostr << j << ", ";
        }
        ostr << endl << i << endl;
    }

}
  • Nice! But I believe in your implementation of operator!=, instead of `fVal < 0 ? fVal > ri.fVal : fVal < ri.fVal;` You want `kStep < 0 ? fVal > ri.fVal : fVal < ri.fVal;` Think for instance in the case when you call `_range( -10, -5, 1 )` – Mateo Feb 01 '19 at 13:52
  • Hi! Thanks for the comment. However, to avoid too many complications this class does not allow such a mix of signs as in your example _range( -10, -5, 1). This is enforced by the assert in the constr, so either all kFrom, kEnd, kStep are all positive or all are negative (no mixture of signs). In the operator != (as I wrote it is a little tricky for the float data), we have to compare only fVal and r.fVal but considering its sign. – Boguslaw Cyganek Feb 03 '19 at 17:53
0

As an iterator:


#include <iostream>

class Range {
    int x, y, z;
public:   
    Range(int x) {this->x = 0; this->y = x; this->z = 1;}
    Range(int x, int y) {this->x = x; this->y = y; this->z = 1;}
    Range(int x, int y, int z) {this->x = x; this->y = y; this->z = z;}

    struct Iterator
    {
        Iterator (int val, int inc) : val{val}, inc{inc} {}
        Iterator& operator++(){val+=inc; return *this;}

        int operator*() const {return val;}
        friend bool operator!=(const Iterator& a, const Iterator& b){return a.val < b.val;}
        private:
        int val, inc;
    };


    Iterator begin() {return Iterator(x,z);}
    Iterator end() {return Iterator(y,z);}
};


    



int main() {

    for (auto i: Range(10)) 
    {
        std::cout << i << ' '; //0 1 2 3 4 5 6 7 8 9 
    }
    std::cout << '\n';
    for (auto i: Range(1,10)) 
    {
        std::cout << i << ' '; //1 2 3 4 5 6 7 8 9 
    }
    std::cout << '\n';
    for (auto i: Range(-10,10,3)) 
    {
        std::cout << i << ' '; //-10 -7 -4 -1 2 5 8 
    }



    return 0;
}