Is there a compact equivalent to Python range() in C++/STL

后端 未结 10 841
[愿得一人]
[愿得一人] 2020-12-04 21:23

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
>>>         


        
相关标签:
10条回答
  • 2020-12-04 21:52

    There is boost::irange:

    std::vector<int> x;
    boost::push_back(x, boost::irange(0, 10));
    
    0 讨论(0)
  • 2020-12-04 21:53

    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));
    }
    
    0 讨论(0)
  • 2020-12-04 21:54

    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
    
    0 讨论(0)
  • 2020-12-04 21:55

    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
    
    0 讨论(0)
  • 2020-12-04 22:03

    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;
        }
    
    }
    
    0 讨论(0)
  • 2020-12-04 22:05

    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';
    
    0 讨论(0)
提交回复
热议问题