c++ Algorithm remove duplicates - both values - c++

EDIT NOTE: This is not a code review, rephrased the question.
Discussion on algorithm implementation at: https://codereview.stackexchange.com/questions/80412/c-algorithm-remove-duplicates-both-values
My Special case:
Home Project, Automatic Downloader for Podcasts.
Overall Algorithm is:
Download a list of available podcasts
hash the podcasts
load metadata + hash of downloaded podcasts from sqlite db
Algorithm this questions is about - throw out all already downloaded.
Download new podcasts
save metadata to sqlite db
Note this algorithm works only to remove 2 duplicates, if there are more than 2 it breaks, please look at the overall algorithm.
Question: is there a name for this algorithm 4 or an aquivalent algorithm?
Question: are there different approaches than my example code below
As a discussion basis the code
Requirements: c++11 compiler e.g gcc 4.9
note: copy paste ready code.
#include <algorithm>
#include <vector>
#include <iostream>
#include <iterator>
#include <string>
template <typename ForwardItr>
ForwardItr doubleEraser(ForwardItr first, ForwardItr last)
{
auto itr = first;
typename std::iterator_traits<ForwardItr>::value_type firstMatch = *first;
bool hasFirstMatch(false);
while(itr != last)
{
auto next = std::next(itr);
if(next != last && *itr == *next)
{
if(!hasFirstMatch)
{
hasFirstMatch = true;
firstMatch = *itr;
}
else
{
if(*itr == firstMatch) // again at first match
{
return itr;
}
}
std::rotate(itr, std::next(itr, 2), last); // throw matched elements to the end of container
}
else
++itr;
}
return last;
}
template <typename T>
void print(T& c)
{
for(auto & element : c)
std::cout << element << " ";
std::cout << "\n";
}
template <class T>
void process(std::vector<T>& t)
{
std::string formating(" \t");
std::cout << "input: " << formating;
print(t);
std::sort(t.begin(), t.end());
std::cout << "sorted:" << formating;
print(t);
auto itr_begin = doubleEraser(t.begin(), t.end());
std::cout << "dEraser:" << formating;
print(t);
t.erase(itr_begin, t.end());
std::cout << "output:" << formating;
print(t);
}
int main()
{
std::vector<int> vec {1,2,3,4,5,6,7,8,9,3,5,6,7,2};
std::vector<char> vec2 {'A', 'C', 'D', 'D', 'G', 'A' };
std::vector<std::string> vec3 {"Hello", "World", "that", "be", "that", "Hello"};
process(vec);
process(vec2);
process(vec3);
}

A simple approach requiring more space complexity. Map unique values and their indexes in reverse order, then just sort by indexes form a helper vector. Similar can be done for string but requires specific compare function.
Edit: for more complete example.
#include <iostream>
#include <vector>
#include <algorithm>
#include <map>
template <typename T>
struct cmp
{
bool operator()(std::pair<T, int>& a,
std::pair<T, int> & b)
{
return a.second < b.second;
}
};
template <typename T, typename Predicate_T>
class RemoveDups
{
std::map<T, int> m_mapped;
std::vector<std::pair<T, int>> m_sorted;
public:
std::vector<T> operator()(const std::vector<T> in)
{
std::vector<T> ret;
ret.reserve(in.size());
for(int i=in.size()-1; i >= 0; i--)
m_mapped[in[i]] = i;
for(auto it : m_mapped)
m_sorted.push_back(it);
std::sort(m_sorted.begin(), m_sorted.end(), Predicate_T());
for (auto it : m_sorted)
ret.push_back(it.first);
return ret;
}
};
int main()
{
std::vector<int> v = {1,1, 2, 2, 7, 2, 2, 7, 7, 2, 3, 8, 4, 5, 3, 2, 3, 2, 6, 2, 3, 2, 9, 10, 1, 2, 2, 1};
std::vector<std::string> s = {"world", "hello", "there", "world", "man", "there", "john", "doe", "doe", "john"};
RemoveDups<int, cmp<int>> c;
v = c(v);
RemoveDups<std::string, cmp<std::string>> vs;
s = vs(s);
for(auto p : v)
std::cout << p<< " ";
std::cout << "\r\n";
for(auto ps : s)
std::cout << ps << " ";
std::cout << "\r\n";
return 0;
}

I think what you're describing (or certainly what you want) is std::unique . It removes all consecutive duplicates in the range (so more than just two duplicates like your algorithm). To work, std::unique requires that the input range is sorted and is implemented as follows:
template<class ForwardIt>
ForwardIt unique(ForwardIt first, ForwardIt last)
{
if (first == last)
return last;
ForwardIt result = first;
while (++first != last) {
if (!(*result == *first)) {
*(++result) = std::move(*first);
}
}
return ++result;
}

Related

Is there a way to iterate a vector in reverse using for each loop? [duplicate]

Is there a container adapter that would reverse the direction of iterators so I can iterate over a container in reverse with range-based for-loop?
With explicit iterators I would convert this:
for (auto i = c.begin(); i != c.end(); ++i) { ...
into this:
for (auto i = c.rbegin(); i != c.rend(); ++i) { ...
I want to convert this:
for (auto& i: c) { ...
to this:
for (auto& i: std::magic_reverse_adapter(c)) { ...
Is there such a thing or do I have to write it myself?
Actually Boost does have such adaptor: boost::adaptors::reverse.
#include <list>
#include <iostream>
#include <boost/range/adaptor/reversed.hpp>
int main()
{
std::list<int> x { 2, 3, 5, 7, 11, 13, 17, 19 };
for (auto i : boost::adaptors::reverse(x))
std::cout << i << '\n';
for (auto i : x)
std::cout << i << '\n';
}
Actually, in C++14 it can be done with a very few lines of code.
This is a very similar in idea to #Paul's solution. Due to things missing from C++11, that solution is a bit unnecessarily bloated (plus defining in std smells). Thanks to C++14 we can make it a lot more readable.
The key observation is that range-based for-loops work by relying on begin() and end() in order to acquire the range's iterators. Thanks to ADL, one doesn't even need to define their custom begin() and end() in the std:: namespace.
Here is a very simple-sample solution:
// -------------------------------------------------------------------
// --- Reversed iterable
template <typename T>
struct reversion_wrapper { T& iterable; };
template <typename T>
auto begin (reversion_wrapper<T> w) { return std::rbegin(w.iterable); }
template <typename T>
auto end (reversion_wrapper<T> w) { return std::rend(w.iterable); }
template <typename T>
reversion_wrapper<T> reverse (T&& iterable) { return { iterable }; }
This works like a charm, for instance:
template <typename T>
void print_iterable (std::ostream& out, const T& iterable)
{
for (auto&& element: iterable)
out << element << ',';
out << '\n';
}
int main (int, char**)
{
using namespace std;
// on prvalues
print_iterable(cout, reverse(initializer_list<int> { 1, 2, 3, 4, }));
// on const lvalue references
const list<int> ints_list { 1, 2, 3, 4, };
for (auto&& el: reverse(ints_list))
cout << el << ',';
cout << '\n';
// on mutable lvalue references
vector<int> ints_vec { 0, 0, 0, 0, };
size_t i = 0;
for (int& el: reverse(ints_vec))
el += i++;
print_iterable(cout, ints_vec);
print_iterable(cout, reverse(ints_vec));
return 0;
}
prints as expected
4,3,2,1,
4,3,2,1,
3,2,1,0,
0,1,2,3,
NOTE std::rbegin(), std::rend(), and std::make_reverse_iterator() are not yet implemented in GCC-4.9. I write these examples according to the standard, but they would not compile in stable g++. Nevertheless, adding temporary stubs for these three functions is very easy. Here is a sample implementation, definitely not complete but works well enough for most cases:
// --------------------------------------------------
template <typename I>
reverse_iterator<I> make_reverse_iterator (I i)
{
return std::reverse_iterator<I> { i };
}
// --------------------------------------------------
template <typename T>
auto rbegin (T& iterable)
{
return make_reverse_iterator(iterable.end());
}
template <typename T>
auto rend (T& iterable)
{
return make_reverse_iterator(iterable.begin());
}
// const container variants
template <typename T>
auto rbegin (const T& iterable)
{
return make_reverse_iterator(iterable.end());
}
template <typename T>
auto rend (const T& iterable)
{
return make_reverse_iterator(iterable.begin());
}
Got this example from cppreference. It works with:
GCC 10.1+ with flag -std=c++20
#include <ranges>
#include <iostream>
int main()
{
static constexpr auto il = {3, 1, 4, 1, 5, 9};
std::ranges::reverse_view rv {il};
for (int i : rv)
std::cout << i << ' ';
std::cout << '\n';
for(int i : il | std::views::reverse)
std::cout << i << ' ';
}
If you can use range v3 , you can use the reverse range adapter ranges::view::reverse which allows you to view the container in reverse.
A minimal working example:
#include <iostream>
#include <vector>
#include <range/v3/view.hpp>
int main()
{
std::vector<int> intVec = {1, 2, 3, 4, 5, 6, 7, 8, 9};
for (auto const& e : ranges::view::reverse(intVec)) {
std::cout << e << " ";
}
std::cout << std::endl;
for (auto const& e : intVec) {
std::cout << e << " ";
}
std::cout << std::endl;
}
See DEMO 1.
Note: As per Eric Niebler, this feature will be available in C++20. This can be used with the <experimental/ranges/range> header. Then the for statement will look like this:
for (auto const& e : view::reverse(intVec)) {
std::cout << e << " ";
}
See DEMO 2
This should work in C++11 without boost:
namespace std {
template<class T>
T begin(std::pair<T, T> p)
{
return p.first;
}
template<class T>
T end(std::pair<T, T> p)
{
return p.second;
}
}
template<class Iterator>
std::reverse_iterator<Iterator> make_reverse_iterator(Iterator it)
{
return std::reverse_iterator<Iterator>(it);
}
template<class Range>
std::pair<std::reverse_iterator<decltype(begin(std::declval<Range>()))>, std::reverse_iterator<decltype(begin(std::declval<Range>()))>> make_reverse_range(Range&& r)
{
return std::make_pair(make_reverse_iterator(begin(r)), make_reverse_iterator(end(r)));
}
for(auto x: make_reverse_range(r))
{
...
}
Does this work for you:
#include <iostream>
#include <list>
#include <boost/range/begin.hpp>
#include <boost/range/end.hpp>
#include <boost/range/iterator_range.hpp>
int main(int argc, char* argv[]){
typedef std::list<int> Nums;
typedef Nums::iterator NumIt;
typedef boost::range_reverse_iterator<Nums>::type RevNumIt;
typedef boost::iterator_range<NumIt> irange_1;
typedef boost::iterator_range<RevNumIt> irange_2;
Nums n = {1, 2, 3, 4, 5, 6, 7, 8};
irange_1 r1 = boost::make_iterator_range( boost::begin(n), boost::end(n) );
irange_2 r2 = boost::make_iterator_range( boost::end(n), boost::begin(n) );
// prints: 1 2 3 4 5 6 7 8
for(auto e : r1)
std::cout << e << ' ';
std::cout << std::endl;
// prints: 8 7 6 5 4 3 2 1
for(auto e : r2)
std::cout << e << ' ';
std::cout << std::endl;
return 0;
}
Sorry but with current C++ (apart from C++20) all these solutions do seem to be inferior to just use index-based for. Nothing here is just "a few lines of code". So, yes: iterate via a simple int-loop. That's the best solution.
template <typename C>
struct reverse_wrapper {
C & c_;
reverse_wrapper(C & c) : c_(c) {}
typename C::reverse_iterator begin() {return c_.rbegin();}
typename C::reverse_iterator end() {return c_.rend(); }
};
template <typename C, size_t N>
struct reverse_wrapper< C[N] >{
C (&c_)[N];
reverse_wrapper( C(&c)[N] ) : c_(c) {}
typename std::reverse_iterator<const C *> begin() { return std::rbegin(c_); }
typename std::reverse_iterator<const C *> end() { return std::rend(c_); }
};
template <typename C>
reverse_wrapper<C> r_wrap(C & c) {
return reverse_wrapper<C>(c);
}
eg:
int main(int argc, const char * argv[]) {
std::vector<int> arr{1, 2, 3, 4, 5};
int arr1[] = {1, 2, 3, 4, 5};
for (auto i : r_wrap(arr)) {
printf("%d ", i);
}
printf("\n");
for (auto i : r_wrap(arr1)) {
printf("%d ", i);
}
printf("\n");
return 0;
}
You could simply use BOOST_REVERSE_FOREACH which iterates backwards. For example, the code
#include <iostream>
#include <boost\foreach.hpp>
int main()
{
int integers[] = { 0, 1, 2, 3, 4 };
BOOST_REVERSE_FOREACH(auto i, integers)
{
std::cout << i << std::endl;
}
return 0;
}
generates the following output:
4
3
2
1
0
If not using C++14, then I find below the simplest solution.
#define METHOD(NAME, ...) auto NAME __VA_ARGS__ -> decltype(m_T.r##NAME) { return m_T.r##NAME; }
template<typename T>
struct Reverse
{
T& m_T;
METHOD(begin());
METHOD(end());
METHOD(begin(), const);
METHOD(end(), const);
};
#undef METHOD
template<typename T>
Reverse<T> MakeReverse (T& t) { return Reverse<T>{t}; }
Demo.
It doesn't work for the containers/data-types (like array), which doesn't have begin/rbegin, end/rend functions.

Check std::vector has duplicates

I want to check if a vector of integers has any duplicates or not, and have to return true if it does. So I try to do something like this:
vector<int> uGuess = {1,2,3,3,4,5}
vector<int> a = uGuess;
sort(a.begin(), a.end());
bool d = unique(a.begin(), a.end());
And this will not work since unqiue cannot be assigned as a bool value.
How should I proceed towards this?
If I were to write a for loop to perform the same action, how should I do that?
The algorithm you're looking for is std::adjacent_find.
// The container must be sorted!
const std::vector<int> sortedVector = {1,2,3,3,4,5};
const bool hasDuplicates = std::adjacent_find(sortedVector.begin(), sortedVector.end()) != sortedVector.end();
Unlike std::unique, std::adjacent_find doesn't modify the container.
As a bonus, std::adjacent_find returns an iterator to the first element in the duplicate "pair":
const auto duplicate = std::adjacent_find(sortedVector.begin(), sortedVector.end());
if (duplicate != sortedVector.end())
std::cout << "Duplicate element = " << *duplicate << "\n";
Looking at google for std::unique I found this page std::unique. I looked at what it did:
Eliminates all except the first element from every consecutive group of equivalent elements from the range [first, last)
So it looks like it does what you want - removes the duplicates.
I then looked at what it returns...
... returns a past-the-end iterator for the new logical end of the range
So the result from std::unique is a sequence which is not necessary the same as the whole vector.
If nothing was removed, the return value would be the end of the vector.
So you want:
vector<int>::iterator it = std::unique(a.begin(), a.end());
bool wasUnique = (it == a.end());
Or for C++11:
auto it = std::unique(a.begin(), a.end());
bool wasUnique = (it == a.end());
Finally for the unique function to work, the vector needs to be sorted, so the complete code would be:
sort(a.begin(), a.end());
auto it = std::unique(a.begin(), a.end());
bool wasUnique = (it == a.end());
You should using set
set<int> s(a.begin(), a.end());
return s.size() != a.size();
If someone is forced to write own algorithm:
bool hasDuplicates(const std::vector<int>& arr) {
for (std::size_t i = 0; i < arr.size(); ++i) {
for (std::size_t j = i + 1; j < arr.size(); ++j) {
if (arr[i] == arr[j])
return true;
}
}
return false;
}
But in real code you should use things that already exist, and in the standard library.
Sort the vector if it's not already sorted, and then use std::unique(), like this:
#include <iostream>
#include <vector>
#include <algorithm>
int main() {
std::vector<int> v = {3, 1, 3, 4, 5};
sort(v.begin(), v.end());
auto it = std::unique(v.begin(), v.end());
std::cout << ((it == v.end()) ? "Unique\n" : "Duplicate(s)\n");
return 0;
}
Output:
Duplicate(s)
So far all these solutions either modify the container or have O(n²) complexity. You can put a std::map to much better use:
#include <algorithm>
#include <iterator>
#include <map>
template <typename Iterator>
bool has_duplicates( Iterator first, Iterator last )
{
std::map <typename std::iterator_traits <Iterator> ::value_type, std::size_t> histogram;
while (first != last)
if (++histogram[ *first++ ] > 1)
return true;
return false;
}
#include <iostream>
#include <vector>
int main()
{
using std::begin;
using std::end;
int a[] = { 2, 3, 5, 7, 11 };
int b[] = { 2, 3, 5, 5, 7 };
std::vector <int> c( begin(a), end(a) );
std::vector <int> d( begin(b), end(b) );
std::cout << std::boolalpha;
std::cout << "a has duplicates false : " << has_duplicates( begin(a), end(a) ) << "\n";
std::cout << "b has duplicates true : " << has_duplicates( begin(b), end(b) ) << "\n";
std::cout << "c has duplicates false : " << has_duplicates( begin(c), end(c) ) << "\n";
std::cout << "d has duplicates true : " << has_duplicates( begin(d), end(d) ) << "\n";
}
If your vector is small, say < 32 objects, or if copying and sorting the objects is expensive or impossible due to lack of move or copy constructor/assignment then a straight O(n^2) compare everything against everything else algorithm is the way to go.
Here is my solution:
template <typename Iterator>
bool has_duplicates( Iterator first, Iterator end ) {
for (auto i = first; i != end; ++i) {
for (auto j = first; i != j; ++j) {
if (*i == *j) return true;
}
}
return false;
}
template <typename Container>
bool has_duplicates(const Container &v) {
for (const auto & i : v) {
for (const auto & j : v) {
if (&i == &j) break;
if (i == j) return true;
}
}
return false;
}

How to count equal, adjacent elements in a vector?

Lets say I have a vector<int> { 1, 1, 2, 3, 3, 3, 1, 1 } and I'd like to convert this into a vector<std::pair<int, int>> { {1, 2}, {2, 1}, {3, 3}, {1, 2} } of 'adjacent element counts':
I'd probably iterate over the vector with a flag indicating the start of a new 'adjacency set' and a counter which counts the number of consecutive elements. I was just wondering if there isn't already a more abstract and elegant solution in the STL as this seems like a very common use-case. Algorithms like unique, adjacent_find or equal_range seem pretty close to what I'm looking for but just not quite the right thing and probably no gain to implementing it from scratch myself.
From an algorithmic point of view the closest thing is run-length encoding I would say. I don't think there is a ready made algorithm to do that, but the code should be trivial:
std::vector<std::pair<int, int>> out;
for (int i: in)
{
if (out.empty() || out.back().first != i)
{
out.emplace_back(i, 1);
}
else
{
++out.back().second;
}
}
Live-example.
Eric Niebler's range library, which, AFAIU is in the process of becoming part of the standard library, has a group_by which is very similar to Python's itertools.groupby, and groups consecutive equivalent elements, just as you need.
To group your vector, you'd start with
const vector<int> l{ 1, 1, 2, 3, 3, 3, 1, 1 };
auto x = l | view::group_by(std::equal_to<int>());
which means that x is a view where adjacent integers belong to a group, if the integers are equal.
Now to iterate, and say, print each consecutive group and its size, you could do the following (I'm sure you can do it better than the following, but this is the limit of my use of this library):
for (auto i = x.begin();i != x.end(); ++i)
cout << *((*i).begin()) << " " << to_vector(*i).size() << endl;
Example
#include <vector>
#include <iostream>
#include <range/v3/all.hpp>
int main(int argc, char **argv) {
const std::vector<int> l{ 1, 1, 2, 3, 3, 3, 1, 1 };
auto x = l | ranges::view::group_by(std::equal_to<int>());
for (auto i = x.begin();i != x.end(); ++i)
std::cout << *((*i).begin()) << " " << ranges::to_vector(*i).size() << std::endl;
}
This prints out
$ ./a.out
1 2
2 1
3 3
1 2
As far as I know there is no such C++ library that will automatically do what you are asking.
Anyway, it is very simple to implement this though. Here is one way:
#include <iostream>
#include <vector>
using namespace std;
void count_equal_elements(vector<int>& vec, vector<pair<int,int> >& result){
if (vec.empty())
return;
int curr = vec[0];
int count = 1;
for (vector<int>::iterator it = vec.begin()+1; it != vec.end(); ++it){
if (curr == *it){
count++;
}
else{
result.push_back(make_pair(curr,count));
curr = *it;
count = 1;
}
}
result.push_back(make_pair(curr,count));
}
See it in ideone.
With std, you may do:
template <typename T>
std::vector<std::pair<T, std::size_t>>
adjacent_count(const std::vector<T>& v)
{
std::vector<std::pair<T, std::size_t>> res;
for (auto it = v.begin(), e = v.end(); it != e; /*Empty*/) {
auto it2 = std::adjacent_find(it, e, std::not_equal_to<>{});
if (it2 != e) {
++it2;
}
res.emplace_back(*it, std::distance(it, it2));
it = it2;
}
return res;
}
Demo
or
template <typename T>
std::vector<std::pair<T, std::size_t>>
adjacent_count(const std::vector<T>& v)
{
std::vector<std::pair<T, std::size_t>> res;
for (auto it = v.begin(), e = v.end(); it != e; /*Empty*/) {
const auto it2 = std::find_if(it, e, [&](const auto&x) { return x != *it; });
res.emplace_back(*it, std::distance(it, it2));
it = it2;
}
return res;
}
Demo

How to iterate over two STL-like containers (Cartesian product)

I'd like to reduce the following with BOOST
typedef std::vector<int>::const_iterator Iterator;
for(Iterator i = v1.begin(), ie = v1.end(); i != ie; ++i) {
for(Iterator j = v2.begin(), je = v2.end(); j != je; ++j) {
doSomething( *i, *j );
}
}
I mean to encapsulate 2 loops in a single construct (with Boost.Foreach, Boost.Range, Boost.Iterator, etc.). The following likes that I'd like to see (It's just idea, not exact what I want to see)
BOOST_FOREACH(boost::tuple<int,int> &p, ..._range(v1, v2)) {
doSomething(p.get<0>(), p.get<1>());
}
How it can be done?
EDIT: By the way, in python you can write just
for (x1,x2,x3) in (l1,l2,l3):
print "do something with", x1, x2, x3
You could use variadic templates to generate the Cartesian product. The code below is baesd on #zch 's excellent answer to another question.
#include <tuple> // make_tuple, tuple
#include <utility> // pair
#include <vector> // vector
namespace detail {
// the lambda is fully bound with one element from each of the ranges
template<class Op>
void insert_tuples(Op op)
{
// evaluating the lambda will insert the currently bound tuple
op();
}
// "peal off" the first range from the remaining tuple of ranges
template<class Op, class InputIterator1, class... InputIterator2>
void insert_tuples(Op op, std::pair<InputIterator1, InputIterator1> head, std::pair<InputIterator2, InputIterator2>... tail)
{
// "peal off" the elements from the first of the remaining ranges
// NOTE: the recursion will effectively generate the multiple nested for-loops
for (auto it = head.first; it != head.second; ++it) {
// bind the first free variable in the lambda, and
// keep one free variable for each of the remaining ranges
detail::insert_tuples(
[=](InputIterator2... elems) mutable { op(it, elems...); },
tail...
);
}
}
} // namespace detail
// convert a tuple of ranges to the range of tuples representing the Cartesian product
template<class OutputIterator, class... InputIterator>
void cartesian_product(OutputIterator result, std::pair<InputIterator, InputIterator>... dimensions)
{
detail::insert_tuples(
[=](InputIterator... elems) mutable { *result++ = std::make_tuple(*elems...); },
dimensions...
);
}
You can call it like this:
int main()
{
bool b[] = { false, true };
int i[] = { 0, 1 };
std::string s[] = { "Hello", "World" };
std::vector< std::tuple<bool, int, std::string> > cp = {
std::make_tuple(false, 0, "Hello") ,
std::make_tuple(false, 0, "World"),
std::make_tuple(false, 1, "Hello"),
std::make_tuple(false, 1, "World"),
std::make_tuple(true, 0, "Hello"),
std::make_tuple(true, 0, "World"),
std::make_tuple(true, 1, "Hello"),
std::make_tuple(true, 1, "World")
};
std::vector< std::tuple<bool, int, std::string> > result;
cartesian_product(
std::back_inserter(result),
std::make_pair(std::begin(b), std::end(b)),
std::make_pair(std::begin(i), std::end(i)),
std::make_pair(std::begin(s), std::end(s))
);
std::cout << std::boolalpha << (result==cp) << "\n";
// now use a single flat loop over result to do your own thing
for (auto t: result) {
std::cout << std::get<0>(t) << ", ";
std::cout << std::get<1>(t) << ", ";
std::cout << std::get<2>(t) << "\n";
}
}
Online output.
I'm not all that familiar with Boost.Range, but you could easily adapt the pair of iterators to use Boost ranges instead. One disadvantage is that it will not be incremental, and you will have to generate the entire Cartesian product up front before you can iterate over it (the code in your question doesn't seem to need a break though).

C++11 reverse range-based for-loop

Is there a container adapter that would reverse the direction of iterators so I can iterate over a container in reverse with range-based for-loop?
With explicit iterators I would convert this:
for (auto i = c.begin(); i != c.end(); ++i) { ...
into this:
for (auto i = c.rbegin(); i != c.rend(); ++i) { ...
I want to convert this:
for (auto& i: c) { ...
to this:
for (auto& i: std::magic_reverse_adapter(c)) { ...
Is there such a thing or do I have to write it myself?
Actually Boost does have such adaptor: boost::adaptors::reverse.
#include <list>
#include <iostream>
#include <boost/range/adaptor/reversed.hpp>
int main()
{
std::list<int> x { 2, 3, 5, 7, 11, 13, 17, 19 };
for (auto i : boost::adaptors::reverse(x))
std::cout << i << '\n';
for (auto i : x)
std::cout << i << '\n';
}
Actually, in C++14 it can be done with a very few lines of code.
This is a very similar in idea to #Paul's solution. Due to things missing from C++11, that solution is a bit unnecessarily bloated (plus defining in std smells). Thanks to C++14 we can make it a lot more readable.
The key observation is that range-based for-loops work by relying on begin() and end() in order to acquire the range's iterators. Thanks to ADL, one doesn't even need to define their custom begin() and end() in the std:: namespace.
Here is a very simple-sample solution:
// -------------------------------------------------------------------
// --- Reversed iterable
template <typename T>
struct reversion_wrapper { T& iterable; };
template <typename T>
auto begin (reversion_wrapper<T> w) { return std::rbegin(w.iterable); }
template <typename T>
auto end (reversion_wrapper<T> w) { return std::rend(w.iterable); }
template <typename T>
reversion_wrapper<T> reverse (T&& iterable) { return { iterable }; }
This works like a charm, for instance:
template <typename T>
void print_iterable (std::ostream& out, const T& iterable)
{
for (auto&& element: iterable)
out << element << ',';
out << '\n';
}
int main (int, char**)
{
using namespace std;
// on prvalues
print_iterable(cout, reverse(initializer_list<int> { 1, 2, 3, 4, }));
// on const lvalue references
const list<int> ints_list { 1, 2, 3, 4, };
for (auto&& el: reverse(ints_list))
cout << el << ',';
cout << '\n';
// on mutable lvalue references
vector<int> ints_vec { 0, 0, 0, 0, };
size_t i = 0;
for (int& el: reverse(ints_vec))
el += i++;
print_iterable(cout, ints_vec);
print_iterable(cout, reverse(ints_vec));
return 0;
}
prints as expected
4,3,2,1,
4,3,2,1,
3,2,1,0,
0,1,2,3,
NOTE std::rbegin(), std::rend(), and std::make_reverse_iterator() are not yet implemented in GCC-4.9. I write these examples according to the standard, but they would not compile in stable g++. Nevertheless, adding temporary stubs for these three functions is very easy. Here is a sample implementation, definitely not complete but works well enough for most cases:
// --------------------------------------------------
template <typename I>
reverse_iterator<I> make_reverse_iterator (I i)
{
return std::reverse_iterator<I> { i };
}
// --------------------------------------------------
template <typename T>
auto rbegin (T& iterable)
{
return make_reverse_iterator(iterable.end());
}
template <typename T>
auto rend (T& iterable)
{
return make_reverse_iterator(iterable.begin());
}
// const container variants
template <typename T>
auto rbegin (const T& iterable)
{
return make_reverse_iterator(iterable.end());
}
template <typename T>
auto rend (const T& iterable)
{
return make_reverse_iterator(iterable.begin());
}
Got this example from cppreference. It works with:
GCC 10.1+ with flag -std=c++20
#include <ranges>
#include <iostream>
int main()
{
static constexpr auto il = {3, 1, 4, 1, 5, 9};
std::ranges::reverse_view rv {il};
for (int i : rv)
std::cout << i << ' ';
std::cout << '\n';
for(int i : il | std::views::reverse)
std::cout << i << ' ';
}
If you can use range v3 , you can use the reverse range adapter ranges::view::reverse which allows you to view the container in reverse.
A minimal working example:
#include <iostream>
#include <vector>
#include <range/v3/view.hpp>
int main()
{
std::vector<int> intVec = {1, 2, 3, 4, 5, 6, 7, 8, 9};
for (auto const& e : ranges::view::reverse(intVec)) {
std::cout << e << " ";
}
std::cout << std::endl;
for (auto const& e : intVec) {
std::cout << e << " ";
}
std::cout << std::endl;
}
See DEMO 1.
Note: As per Eric Niebler, this feature will be available in C++20. This can be used with the <experimental/ranges/range> header. Then the for statement will look like this:
for (auto const& e : view::reverse(intVec)) {
std::cout << e << " ";
}
See DEMO 2
This should work in C++11 without boost:
namespace std {
template<class T>
T begin(std::pair<T, T> p)
{
return p.first;
}
template<class T>
T end(std::pair<T, T> p)
{
return p.second;
}
}
template<class Iterator>
std::reverse_iterator<Iterator> make_reverse_iterator(Iterator it)
{
return std::reverse_iterator<Iterator>(it);
}
template<class Range>
std::pair<std::reverse_iterator<decltype(begin(std::declval<Range>()))>, std::reverse_iterator<decltype(begin(std::declval<Range>()))>> make_reverse_range(Range&& r)
{
return std::make_pair(make_reverse_iterator(begin(r)), make_reverse_iterator(end(r)));
}
for(auto x: make_reverse_range(r))
{
...
}
Does this work for you:
#include <iostream>
#include <list>
#include <boost/range/begin.hpp>
#include <boost/range/end.hpp>
#include <boost/range/iterator_range.hpp>
int main(int argc, char* argv[]){
typedef std::list<int> Nums;
typedef Nums::iterator NumIt;
typedef boost::range_reverse_iterator<Nums>::type RevNumIt;
typedef boost::iterator_range<NumIt> irange_1;
typedef boost::iterator_range<RevNumIt> irange_2;
Nums n = {1, 2, 3, 4, 5, 6, 7, 8};
irange_1 r1 = boost::make_iterator_range( boost::begin(n), boost::end(n) );
irange_2 r2 = boost::make_iterator_range( boost::end(n), boost::begin(n) );
// prints: 1 2 3 4 5 6 7 8
for(auto e : r1)
std::cout << e << ' ';
std::cout << std::endl;
// prints: 8 7 6 5 4 3 2 1
for(auto e : r2)
std::cout << e << ' ';
std::cout << std::endl;
return 0;
}
Sorry but with current C++ (apart from C++20) all these solutions do seem to be inferior to just use index-based for. Nothing here is just "a few lines of code". So, yes: iterate via a simple int-loop. That's the best solution.
template <typename C>
struct reverse_wrapper {
C & c_;
reverse_wrapper(C & c) : c_(c) {}
typename C::reverse_iterator begin() {return c_.rbegin();}
typename C::reverse_iterator end() {return c_.rend(); }
};
template <typename C, size_t N>
struct reverse_wrapper< C[N] >{
C (&c_)[N];
reverse_wrapper( C(&c)[N] ) : c_(c) {}
typename std::reverse_iterator<const C *> begin() { return std::rbegin(c_); }
typename std::reverse_iterator<const C *> end() { return std::rend(c_); }
};
template <typename C>
reverse_wrapper<C> r_wrap(C & c) {
return reverse_wrapper<C>(c);
}
eg:
int main(int argc, const char * argv[]) {
std::vector<int> arr{1, 2, 3, 4, 5};
int arr1[] = {1, 2, 3, 4, 5};
for (auto i : r_wrap(arr)) {
printf("%d ", i);
}
printf("\n");
for (auto i : r_wrap(arr1)) {
printf("%d ", i);
}
printf("\n");
return 0;
}
You could simply use BOOST_REVERSE_FOREACH which iterates backwards. For example, the code
#include <iostream>
#include <boost\foreach.hpp>
int main()
{
int integers[] = { 0, 1, 2, 3, 4 };
BOOST_REVERSE_FOREACH(auto i, integers)
{
std::cout << i << std::endl;
}
return 0;
}
generates the following output:
4
3
2
1
0
If not using C++14, then I find below the simplest solution.
#define METHOD(NAME, ...) auto NAME __VA_ARGS__ -> decltype(m_T.r##NAME) { return m_T.r##NAME; }
template<typename T>
struct Reverse
{
T& m_T;
METHOD(begin());
METHOD(end());
METHOD(begin(), const);
METHOD(end(), const);
};
#undef METHOD
template<typename T>
Reverse<T> MakeReverse (T& t) { return Reverse<T>{t}; }
Demo.
It doesn't work for the containers/data-types (like array), which doesn't have begin/rbegin, end/rend functions.