Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to slice with for-range loop ? C++0x

Tags:

c++

c++11

Using range based for loops in C++0X, I know we'll be able to do :

std::vector<int> numbers = generateNumbers();

for( int k : numbers )
{
   processNumber( k );
}

(might be even simpler to write with lambda)

But how should i do if I only want to apply processNumber( k ) to a part of numbers? For example, how should I write this for loop for to apply processNumber() to the half (head or tail) of the numbers? Is "slicing" allowed like in Python or Ruby?

like image 696
Klaim Avatar asked Feb 03 '10 22:02

Klaim


People also ask

Can we use for loop in slices?

Given this practice, you can now write a for loop to yield slice1 , slice2 , and slice3 in a row. We did it by defining a variable gap . There is always a gap of 5 between the starting index and the ending index because the slices we want are of length 5.

When to use range-based for loop c++?

Use the range-based for statement to construct loops that must execute through a range, which is defined as anything that you can iterate through—for example, std::vector , or any other C++ Standard Library sequence whose range is defined by a begin() and end() .

How does range for loop work in c++?

C++11 introduced the ranged for loop. This for loop is specifically used with collections such as arrays and vectors. Here, the ranged for loop iterates the array num from beginning to end. The int variable var stores the value of the array element in each iteration.


2 Answers

You can use the "sliced" range adaptor from the Boost.Range library:

#include <boost/range/adaptor/sliced.hpp>

using boost::adaptors::sliced;

...

std::vector<int> numbers = generateNumbers();
for( int k : numbers | sliced(0, numbers.size() / 2))
{
     processNumber( k );
}   
like image 79
HighCommander4 Avatar answered Sep 18 '22 17:09

HighCommander4


One possibility might be boost's iterator_range

(Not having a compiler which supports range-based for, using BOOST_FOREACH instead. I'd expect range-based for work the same, as long as the container or range has the begin and end method.)

#include <boost/foreach.hpp>
#include <boost/range/iterator_range.hpp>
#include <iostream>
#include <vector>

int main()
{
    std::vector<int> v{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
    BOOST_FOREACH(int n, boost::make_iterator_range(v.begin(), v.begin() + v.size() / 2)) {
        std::cout << n << '\n';
    }
}

For convenience you could also make your own slice function, so it would accept indices instead of iterators. Again, it could be based on boost.iterator_range, or not:

#include <cstddef>
#include <iterator>

template <class Iterator>
class iter_pair
{
public:
    typedef Iterator iterator;
    typedef Iterator const_iterator; //BOOST_FOREACH appears to want this
    iter_pair(iterator first, iterator last): first(first), last(last) {}
    iterator begin() const { return first; }
    iterator end() const { return last; }
private:
    iterator first, last;
};

template <class Container>
struct iterator_type
{
    typedef typename Container::iterator type;
};

template <class Container>
struct iterator_type<const Container>
{
    typedef typename Container::const_iterator type;
};

template <class Container>
iter_pair<typename iterator_type<Container>::type>
    slice(Container& c, size_t i_first, size_t i_last)
{
    typedef typename iterator_type<Container>::type iterator;
    iterator first = c.begin();        
    std::advance(first, i_first);
    iterator last = first;
    std::advance(last, i_last - i_first);
    return iter_pair<iterator>(first, last);
}

template <class Container>
iter_pair<typename iterator_type<Container>::type>
    slice(Container& c, size_t i_last)
{
    return slice(c, 0, i_last);
}

//could probably also be overloaded for arrays

#include <cctype>
#include <string>
#include <boost/foreach.hpp>
#include <iostream>

int main()
{
    std::string s("Hello world, la-la-la!");
    BOOST_FOREACH( char& c, slice(s, 2, 11)) {
        if (c == 'l')
            c = std::toupper(c);
    }
    const std::string& r = s;
    BOOST_FOREACH( char c, slice(r, r.size() - 1) ) {
        std::cout << c << " ";
    }
    std::cout << '\n';
}

Generally one would probably be working with iterators in the first place, so it might not be that useful.

like image 28
UncleBens Avatar answered Sep 18 '22 17:09

UncleBens