¿Existe un compacto equivalente al rango de Python () en C ++ / STL?

¿Cómo puedo hacer el equivalente de lo siguiente utilizando C ++ / STL? Quiero rellenar un std::vector con un rango de valores [min, max).

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

Supongo que podría usar std::generate_n y proporcionar un functor para generar la secuencia, pero me preguntaba si hay una forma más sucinta de hacerlo utilizando STL.

En C ++ 11, hay std::iota :

 std::vector x(10); std::iota(std::begin(x), std::end(x), 0); //0 is the starting number 

Hay impulso :: irange :

 std::vector x; boost::push_back(x, boost::irange(0, 10)); 

Terminé escribiendo algunas funciones de utilidad para hacer esto. Puedes usarlos de la siguiente manera:

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

El código:

 #include  #include  template  std::vector range(IntType start, IntType stop, IntType step) { if (step == IntType(0)) { throw std::invalid_argument("step for range must be non-zero"); } std::vector result; IntType i = start; while ((step > 0) ? (i < stop) : (i > stop)) { result.push_back(i); i += step; } return result; } template  std::vector range(IntType start, IntType stop) { return range(start, stop, IntType(1)); } template  std::vector range(IntType stop) { return range(IntType(0), stop, IntType(1)); } 

Existe boost::irange , pero no proporciona puntos de flotación, pasos negativos y no puede inicializar directamente los contenedores STL.

También hay numeric_range en mi biblioteca de RO

En RO, para inicializar un vector:

 vector V=range(10); 

Ejemplo de cortar y pegar desde la página doc (evaluador de fragmentos de scc – c ++):

 // [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')" abcdefghijklmnopqrstu vwxyz // no need for verbose iota. (vint - vector) 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 

He estado usando esta biblioteca para este propósito exacto durante años:

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

Funciona muy bien y los proxies están optimizados.

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

No conozco una forma de hacerlo como en Python, pero obviamente hay otra alternativa para hacerlo en bucle:

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

La respuesta de Chris es mejor si tienes c ++ 11

Para aquellos que no pueden usar C ++ 11 o bibliotecas:

 vector x(10,0); // 0 is the starting number, 10 is the range size transform(x.begin(),x.end(),++x.begin(),bind2nd(plus(),1)); // 1 is the increment 

Si no puedes usar C ++ 11, puedes usar std::partial_sum para generar números del 1 al 10. Y si necesitas números del 0 al 9, puedes restar 1 usando la transformación:

 std::vector 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(), 1)); 

Una función de rango () similar a la siguiente ayudará:

 #include  #include  #include  #include  using namespace std; // define range function (only once) template  vector  range(T N1, T N2) { vector numbers(N2-N1); iota(numbers.begin(), numbers.end(), N1); return numbers; } vector  arr = range(0, 10); vector  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 

Hace algún tiempo escribí la siguiente clase de rango , que se comporta como el rango de Python (ponlo en el “rango.h”):

 #pragma once #include  #include  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; 

Y algún código de prueba se parece al siguiente:

 #include "range.h" #include  #include  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; } }