在 C + +/STL 中是否有一个与 Python range()等价的压缩

如何使用 C + +/STL 执行以下等效操作?我想用一个值范围[ min,max ]来填充 std::vector

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

我想我可以使用 std::generate_n并提供一个函数来生成序列,但是我想知道是否有一种更简洁的方法来使用 STL?

44105 次浏览

在 C + + 11中,有 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引入了一个延迟版本(就像 Python 一样)作为范围库的一部分:

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

我不知道有什么方法可以像 python 那样做,但另一种方法显然是 for 循环:

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

如果有 c + + 11,Chris 的答案会更好

还有 是 irange:

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

boost::irange,但它不提供浮点数,负步骤,不能直接初始化 stl 容器。

我的 RO 库中也有 numeric_range

在 RO 中,初始化向量:

vector<int> V=range(10);

来自 doc 页面的剪切-n-粘贴示例(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')"
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

对于那些不能使用 C + + 11或库的人:

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

如果不能使用 C + + 11,可以使用 std::partial_sum生成从1到10的数字。如果你需要从0到9的数字,你可以使用转换来减去1:

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

最后,我编写了一些实用函数来实现这一点:

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

密码:

#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));
}

多年来,我一直用这个图书馆来达到这个目的:

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

工作得非常好,代理也得到了优化。

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

一个与下面类似的 range ()函数将有所帮助:

#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

不久前,我编写了以下 这是我们的地盘类,其行为类似于 Python range (将其放在“ 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;

一些测试代码如下所示:

#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;
}


}

作为迭代器:


#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;
}