Blog coding and discussion of coding about JavaScript, PHP, CGI, general web building etc.

Thursday, March 3, 2016

C++ range/xrange equivalent in STL or boost?

C++ range/xrange equivalent in STL or boost?


Is there C++ equivalent for python Xrange generator in either STL or boost?

xrange basically generates incremented number with each call to ++ operator. the constructor is like this:

xrange(first, last, increment)  

was hoping to do something like this using boost for each:

foreach(int i, xrange(N))  

I. am aware of the for loop. in my opinion they are too much boilerplate.

Thanks

my reasons:

my main reason for wanting to do so is because i use speech to text software, and programming loop usual way is difficult, even if using code completion. It is much more efficient to have pronounceable constructs.

many loops start with zero and increment by one, which is default for range. I find python construct more intuitive

 for(int i = 0; i < N; ++i)   foreach(int i, range(N))  

functions which need to take range as argument:

 Function(int start, int and, int inc);   function(xrange r);  

I understand differences between languages, however if a particular construct in python is very useful for me and can be implemented efficiently in C++, I do not see a reason not to use it. For each construct is foreign to C++ as well however people use it.

I put my implementation at the bottom of the page as well the example usage.

in my domain i work with multidimensional arrays, often rank 4 tensor. so I would often end up with 4 nested loops with different ranges/increments to compute normalization, indexes, etc. those are not necessarily performance loops, and I am more concerned with correctness readability and ability to modify.

for example

int function(int ifirst, int ilast, int jfirst, int jlast, ...);  versus  int function(range irange, range jrange, ...);  

In the above, if different strids are needed, you have to pass more variables, modify loops, etc. eventually you end up with a mass of integers/nearly identical loops.

foreach and range solve my problem exactly. familiarity to average C++ programmer is not high on my list of concerns - problem domain is a rather obscure, there is a lot of meta-programming, SSE intrinsic, generated code.

Answer by Chinmay Kanchi for C++ range/xrange equivalent in STL or boost?


You're trying to bring a python idiom into C++. That's unncessary. Use

for(int i=initVal;i

to achieve this. In Python, the for(i in xrange(init, rng, increment)) form is necessary because Python doesn't provide a simple for loop, only a for-each type construct. So you can iterate only over a sequence or a generator. This is simply unnecessary and almost certainly bad practice in a language that provides a for(;;) syntax.

EDIT: As a completely non-recommended aside, the closest I can get to the for i xrange(first, last, inc) syntax in C++ is:

#include     using namespace std;    int xrange(unsigned int last, unsigned int first=0, unsigned int inc=1)  {      static int i = first;      return (i

Not that while this loops the correct number of times, i varies from first+inc to last and NOT first to last-inc as in Python. Also, the function can only work reliably with unsigned values, as when i==0, the while loop will exit. Do not use this function. I only added this code here to demonstrate that something of the sort is indeed possible. There are also several other caveats and gotchas (the code won't really work for first!=0 on subsequent function calls, for example)

Answer by Loki Astari for C++ range/xrange equivalent in STL or boost?


The for loop handles that nearly automatically:

for(int loop=first;loop < last;loop += increment)  {    /// Do Stuff.  }  

Answer by GManNickG for C++ range/xrange equivalent in STL or boost?


What you're doing isn't go to work as efficiently as you intend. BOOST_FOREACH evaluates it's arguments only once. This means you need xrange to produce an iteratable container full of your values.

That is, it could look like this (note, could be more generic, like taking an advancement functor, etc.):

template   std::vector xrange(const T& pBegin, const T& pEnd)  {      std::vector v;        for (T i = pBegin, i < pEnd; ++i)      {          v.push_back(i);      }        return v;  }  

But all you've done is:

  1. Move the for-loop into a function,
  2. Wasted time and resources allocating a vector that will die shortly after

Rather, just use the for-loop directly, like I previously mentioned and other are mentioning.

If you're really against a loop (keep in mind you don't program to save keystrokes!), you could probably use a macro and some magic (untested):

#define FOR_N(v, s, e)  for (BOOST_AUTO(v, s); v < e; ++v)    #define for_n FOR_N // better looking    for_n(i, 0, N)  {      // use i;  }  

Of course now you have to include another file, and this code is :\

Answer by UncleBens for C++ range/xrange equivalent in STL or boost?


Boost has counting_iterator as far as I know, which seems to allow only incrementing in steps of 1. For full xrange functionality you might need to implement a similar iterator yourself.

All in all it could look like this (edit: added an iterator for the third overload of xrange, to play around with boost's iterator facade):

#include   #include   #include   #include   #include   #include     template   boost::iterator_range > xrange(T to)  {      //these assertions are somewhat problematic:      //might produce warnings, if T is unsigned      assert(T() <= to);      return boost::make_iterator_range(boost::counting_iterator(0), boost::counting_iterator(to));  }    template   boost::iterator_range > xrange(T from, T to)  {      assert(from <= to);      return boost::make_iterator_range(boost::counting_iterator(from), boost::counting_iterator(to));  }    //iterator that can do increments in steps (positive and negative)  template   class xrange_iterator:      public boost::iterator_facade, const T, std::forward_iterator_tag>  {      T value, incr;  public:      xrange_iterator(T value, T incr = T()): value(value), incr(incr) {}  private:      friend class boost::iterator_core_access;      void increment() { value += incr; }      bool equal(const xrange_iterator& other) const      {          //this is probably somewhat problematic, assuming that the "end iterator"          //is always the right-hand value?          return (incr >= 0 && value >= other.value) || (incr < 0 && value <= other.value);      }      const T& dereference() const { return value; }  };    template   boost::iterator_range > xrange(T from, T to, T increment)  {      assert((increment >= T() && from <= to) || (increment < T() && from >= to));      return boost::make_iterator_range(xrange_iterator(from, increment), xrange_iterator(to));  }    int main()  {      BOOST_FOREACH(int i, xrange(10)) {          std::cout << i << ' ';      }      BOOST_FOREACH(int i, xrange(10, 20)) {          std::cout << i << ' ';      }      std::cout << '\n';      BOOST_FOREACH(int i, xrange(0, 46, 5)) {          std::cout << i << ' ';      }      BOOST_FOREACH(int i, xrange(10, 0, -1)) {          std::cout << i << ' ';      }  }  

As others are saying, I don't see this buying you much over a normal for loop.

Answer by Anycorn for C++ range/xrange equivalent in STL or boost?


well, here is what i wrote, since there does not seem to be one. the generator does not use any internal storage besides single integer. range object can be passed around and used in nested loops.

there is a small test case.

#include "iostream"  #include "foreach.hpp"    #include "boost/iterator/iterator_categories.hpp"    struct range {      struct iterator_type {      typedef int value_type;      typedef int difference_type;      typedef boost::single_pass_traversal_tag iterator_category;      typedef const value_type* pointer;      typedef const value_type & reference;        mutable value_type value;      const difference_type increment;        iterator_type(value_type value, difference_type increment = 0)        : value(value), increment(increment) {}        bool operator==(const iterator_type &rhs) const {        return value >= rhs.value;      }      value_type operator++() const { return value += increment; }      operator pointer() const { return &value; }    };      typedef iterator_type iterator;    typedef const iterator_type const_iterator;      int first_, last_, increment_;      range(int last) : first_(0), last_(last), increment_(1) {}    range(int first, int last, int increment = 1)      : first_(first), last_(last), increment_(increment) {}      iterator begin() const {return iterator(first_, increment_);}    iterator end() const {return iterator(last_);}  };    int test(const range & range0, const range & range1){    foreach(int i, range0) {      foreach(int j, range1) {        std::cout << i << " " << j << "\n";      }    }  }    int main() {    test(range(6), range(3, 10, 3));  }  

Answer by ephemient for C++ range/xrange equivalent in STL or boost?


std::iota (not yet standardized) is kinda like range. Doesn't make things any shorter or clearer than an explicit for loop, though.

#include   #include   #include   #include   #include   int main() {      std::vector nums(5);      std::iota(nums.begin(), nums.end(), 1);      std::copy(nums.begin(), nums.end(),              std::ostream_iterator(std::cout, " "));      std::cout << std::endl;      return 0;  }  

Compile with g++ -std=c++0x; this prints "1 2 3 4 5 \n".

Answer by jalf for C++ range/xrange equivalent in STL or boost?


my main reason for wanting to do so is because i use speech to text software, and programming loop usual way is difficult, even if using code completion. It is much more efficient to have pronounceable constructs.

That makes sense. But couldn't a simple macro solve this problem? #define for_i_to(N, body) for (int i = 0; i < N; ++i) { body }

or something similar. Or avoid the loop entirely and use the standard library algorithms. (std::for_each(range.begin(), rang.end(), myfunctor()) seems easier to pronounce)

many loops start with zero and increment by one, which is default for range. I find python construct more intuitive

You're wrong. The Python version is more intuitive to a Python programmer. And it may be more intuitive to a non-programmer. But you're writing C++ code. Your goal should be to make it intuitive to a C++ programmer. And C++ programmer know for-loops and they know the standard library algorithms. Stick to using those. (Or stick to writing Python)

functions which need to take range as argument:

Function(int start, int and, int inc);  function(xrange r);  

Or the idiomatic C++ version:

template   void function(iter_type first, iter_type last);  

In C++, ranges are represented by iterator pairs. Not integers. If you're going to write code in a new language, respect the conventions of that language. Even if it means you have to adapt and change some habits.

If you're not willing to do that, stick with the language you know.

Trying to turn language X into language Y is always the wrong thing to do. It own't work, and it'll confuse the language X programmers who are going to maintain (or just read) your code.

Answer by jalf for C++ range/xrange equivalent in STL or boost?


Since we don't really know what you actually want to use this for, I'm assuming your test case is representative. And then plain simple for loops are a whole lot simpler and more readable:

int main() {    for (int i = 0; i <= 6; ++i){      for (int j = 3; j <= 10; j += 3){        std::cout << i << " " << j << "\n";      }    }  }  

A C++ programmer can walk in from the street and understand this function without having to look up complex classes elsewhere. And it's 5 lines instead of your 60. Of course if you have 400 loops exactly like these, then yes, you'd save some effort by using your range object. Or you could just wrap these two loops inside a helper function, and call that whenever you needed.

We don't really have enough information to say what's wrong with simple for loops, or what would be a suitable replacement. The loops here solve your problem with far less complexity and far fewer lines of code than your sample implementation. If this is a bad solution, tell us your requirements (as in what problem you need to solve, rather than "I want python-style loops in C++")

Answer by Paul Brannan for C++ range/xrange equivalent in STL or boost?


Since I've started to use BOOST_FOREACH for all my iteration (probably a misguided idea, but that's another story), here's another use for aaa's range class:

std::vector vec;  // ... fill the vector ...  BOOST_FOREACH(size_t idx, make_range(0, vec.size()))  {    // ... do some stuff ...  }  

(yes, range should be templatized so I can use user-defined integral types with it)

And here's make_range():

template  range make_range(T const & start, T const & end)  {    return range(start, end);  }  

See also:

http://groups.google.com/group/boost-list/browse_thread/thread/3e11117be9639bd

and:

https://svn.boost.org/trac/boost/ticket/3469

which propose similar solutions.

And I've just found boost::integer_range; with the above example, the code would look like:

using namespace boost;  std::vector vec;  // ... fill the vector ...  BOOST_FOREACH(size_t idx, make_integer_range(0, vec.size()))  {    // ... do some stuff ...  }  

Answer by Viktor Sehr for C++ range/xrange equivalent in STL or boost?


Keep it simple, make a stupid macro;

#define for_range(VARNAME, START, STOP, INCREMENT) \  for(int VARNAME = START, int STOP_ = STOP, INCREMENT_ = INCREMENT; VARNAME != STOP_; VARNAME += INCREMENT_)  

and use as;

for_range(i, 10, 5, -1)    cout << i << endl;  

Answer by sehe for C++ range/xrange equivalent in STL or boost?


Boost irange should really be the answer (ThxPaul Brannan)

I'm adding my answer to provide a compelling example of very valid use-cases that are not served well by manual looping:

#include   #include   #include     using namespace boost::adaptors;    static int mod7(int v)       { return v % 7; }    int main()   {      std::vector v;        boost::copy(              boost::irange(1,100) | transformed(mod7),               std::back_inserter(v));        boost::sort(v);        boost::copy(              v | reversed | uniqued,               std::ostream_iterator(std::cout, ", "));  }  

Output: 6, 5, 4, 3, 2, 1, 0,

Note how this resembles generators/comprehensions (functional languages) and enumerables (C#)

Update I just thought I'd mention the following (highly inflexible) idiom that C++11 allows:

for (int x : {1,2,3,4,5,6,7})      std::cout << x << std::endl;  

of course you could marry it with irange:

for (int x : boost::irange(1,8))      std::cout << x << std::endl;  


Fatal error: Call to a member function getElementsByTagName() on a non-object in D:\XAMPP INSTALLASTION\xampp\htdocs\endunpratama9i\www-stackoverflow-info-proses.php on line 72

0 comments:

Post a Comment

Popular Posts

Powered by Blogger.