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).
Related
I have a vector of integers:
std::vector<int> values = {1,2,3,4,5,6,7,8,9,10};
Given that values.size() will always be even.
I simply want to convert the adjacent elements into a pair, like this:
std::vector<std::pair<int,int>> values = { {1,2}, {3,4} , {5,6}, {7,8} ,{9,10} };
I.e., the two adjacent elements are joined into a pair.
What STL algorithm can I use to easily achieve this? Is it possible to achieve this through some standard algorithms?
Of course, I can easily write an old school indexed for loop to achieve that. But I want to know what the simplest solution could look like using rangebased for loops or any other STL algorithm, like std::transform, etc.
Once we have C++23's extension to <ranges>, you can get most of the way there with std::ranges::views::chunk, although that produces subranges, not pairs.
#include <iostream>
#include <ranges>
#include <vector>
int main()
{
std::vector<int> values = {1,2,3,4,5,6,7,8,9,10};
auto chunk_to_pair = [](auto chunk)
{
return std::pair(*chunk.begin(), *std::next(chunk.begin()));
};
for (auto [first, second] : values | std::ranges::views::chunk(2) | std::ranges::views::transform(chunk_to_pair))
{
std::cout << first << second << std::endl;
}
}
Alternatively, you could achieve a similar result by ziping a pair of strided views
#include <iostream>
#include <ranges>
#include <vector>
int main()
{
std::vector<int> values = {1,2,3,4,5,6,7,8,9,10};
auto odds = values | std::ranges::views::drop(0) | std::ranges::views::stride(2);
auto evens = values | std::ranges::views::drop(1) | std::ranges::views::stride(2);
for (auto [first, second] : std::ranges::views::zip(odds, evens))
{
std::cout << first << second << std::endl;
}
}
That last one can be generalised to n-tuples
template <size_t N>
struct tuple_chunk_t
{
template <typename R, size_t... Is>
auto impl(R && r, std::index_sequence<Is...>)
{
using namespace ranges::view;
return zip(r | drop(Is) | stride(N)...);
}
template <typename R>
auto operator()(R && r) const
{
return impl(std::forward<R>(r), std::make_index_sequence<N>{});
}
template <typename R>
friend auto operator|(R && r, chunk_t)
{
return impl(std::forward<R>(r), std::make_index_sequence<N>{});
}
};
template <size_t N>
constexpr tuple_chunk_t<N> tuple_chunk;
I'm not sure why you would require a standard algorithm when writing it yourself is roughly 5 lines of code (plus boilerplate):
template<class T>
std::vector<std::pair<T, T>> group_pairs(const std::vector<T>& values)
{
assert(values.size() % 2 == 0);
auto output = std::vector<std::pair<T, T>>();
output.reserve(values.size()/2);
for(size_t i = 0; i < values.size(); i+=2)
output.emplace_back(values[i], values[i+1]);
return output;
}
And call it like so:
std::vector<int> values = {1,2,3,4,5,6,7,8,9,10};
auto result = group_pairs(values)
Live Demo
I am not aware of a standard algorithm that does what you want directly (though I am not very familiar with C++20 and beyond). You can always write a loop and most loops can be expressed via std::for_each which is a standard algorithm.
As you are accumulating elements in pairs, I would give std::accumulate a try:
#include <vector>
#include <numeric>
#include <iostream>
struct pair_accumulator {
std::vector<std::pair<int,int>> result;
int temp = 0;
bool set = false;
pair_accumulator& operator+(int x){
if (set) {
result.push_back({temp,x});
set = false;
} else {
temp = x;
set = true;
}
return *this;
}
};
int main() {
std::vector<int> values = {1,2,3,4,5,6,7,8,9,10};
auto x = std::accumulate(values.begin(),values.end(),pair_accumulator{}).result;
for (const auto& e : x) {
std::cout << e.first << " " << e.second << "\n";
}
}
Whether this is simpler than writing a plain loop is questionable admittedly.
If possible I would try to not transform the vector. Instead of accessing result[i].first you can as well use values[i*2] and similar for second. If this is not feasible the next option is to populate a std::vector<std::pair<int,int>> from the start so you don't have to do the transformation. For the first, depending on what you need in details, the following might be a start:
#include <vector>
#include <iostream>
struct view_as_pairs {
std::vector<int>& values;
struct proxy {
std::vector<int>::iterator it;
int& first() { return *it;}
int& second() { return *(it +1); }
};
proxy operator[](size_t index){
return proxy{values.begin() + index*2};
}
size_t size() { return values.size() / 2;}
};
int main() {
std::vector<int> values = {1,2,3,4,5,6,7,8,9,10};
view_as_pairs v{values};
for (size_t i=0; i < v.size(); ++i){
std::cout << v[i].first() << " " << v[i].second() << "\n";
}
}
TL;DR: Consider if you can avoid the transformation. If you cannot avoid it, it is probably cleanest to write a loop. Standard algorithms help often but not always.
OK, I hinted in the comments about using std::adjacent_find, so here is how you would do this.
And yes, many (even myself) considers this a hack, where we are using a tool meant for something else to make short work of solving a seemingly unrelated problem:
#include <algorithm>
#include <iostream>
#include <utility>
#include <vector>
int main()
{
//Test data
std::vector<int> v = {1,2,3,4,5,6,7,8,9,10};
// results
std::vector<std::pair<int,int>> result;
// save flag
bool save_it = true;
// Use std::adjacent_find
std::adjacent_find(v.begin(), v.end(), [&](int n1, int n2)
{ if (save_it) result.push_back({n1,n2}); save_it = !save_it; return false; });
for (auto& pr : result)
std::cout << pr.first << " " << pr.second << "\n";
}
Output:
1 2
3 4
5 6
7 8
9 10
The way it works is we ignore the second, fourth, sixth, etc. pairs, and only save the first, third, fifth, etc. pairs. That's controlled by a boolean flag variable, save_it.
Note that since we want to process all pairs, the std::adjacent_find predicate always returns false. That's the hackish part of this solution.
The solutions so far try to use the std::vector iterators as input to the algorithms directly. How about defining a custom iterator that returns a std::pair and has strides of 2? Creating the vector of pairs is then a one-liner that uses std::copy. The iterator effectively provides a "view" onto the original vector in terms of pairs. This also allows the use of many of the standard algorithms. The following example could also be generalized quite a bit to work with most container iterators, i.e. you do the difficult work of defining such an iterator once and then you can apply it to all sorts of containers and algorithms. Live example: https://godbolt.org/z/ceEsvKhzd
#include <vector>
#include <algorithm>
#include <iostream>
#include <cassert>
struct pair_iterator {
using difference_type = std::vector<int>::const_iterator::difference_type;
using value_type = std::pair<int, int>;
using pointer = value_type*;
using reference = value_type; // Not a pair&, but that is ok for LegacyIterator
// Can't be forward_iterator_tag because "reference" is not a pair&
using iterator_category = std::input_iterator_tag;
reference operator*()const { return {*base_iter, *(base_iter + 1)}; }
pair_iterator & operator++() { base_iter += 2; return *this; }
pair_iterator operator++(int) { auto ret = *this; ++(*this); return ret; }
friend bool operator==(pair_iterator lhs, pair_iterator rhs){
return lhs.base_iter == rhs.base_iter;
}
friend bool operator!=(pair_iterator lhs, pair_iterator rhs){
return lhs.base_iter != rhs.base_iter;
}
std::vector<int>::const_iterator base_iter{};
};
auto pair_begin(std::vector<int> const & v){ assert(v.size()%2==0); return pair_iterator{v.begin()}; }
auto pair_end(std::vector<int> const & v){ assert(v.size()%2==0); return pair_iterator{v.end()}; }
int main()
{
std::vector<int> values = {1,2,3,4,5,6,7,8,9,10};
std::vector<std::pair<int, int>> pair_values;
std::copy(pair_begin(values), pair_end(values), std::back_inserter(pair_values));
for (auto const & pair : pair_values) {
std::cout << "{" << pair.first << "," << pair.second << "} ";
}
std::cout << std::endl;
}
I have a C++ vector of doubles, which is guaranteed to have an even number of elements. This vector stores the coordinates of a set of points as x, y coordinates:
A[2 * i ] is the x coordinate of the i'th point.
A[2 * i + 1] is the y coordinate of the i'th point.
How to implement an iterator that allows me to use STL style algorithms (one that takes an iterator range, where dereferencing an iterator gives back the pair of doubles corresponding to the x, y coordinates of the corresponding point) ?
I'm using C++17 if that helps.
We can use range-v3, with two adapters:
chunk(n) takes a range and adapts it into a range of non-overlapping ranges of size n
transform(f) takes a range of x and adapts it into a range of f(x)
Putting those together we can create an adaptor which takes a range and yields a range of non-overlapping pairs:
auto into_pairs = rv::chunk(2)
| rv::transform([](auto&& r){ return std::pair(r[0], r[1]); });
Using the r[0] syntax assumes that the input range is random-access, which in this case is fine since we know we want to use it on a vector, but it can also be generalized to work for forward-only ranges at the cost of a bit more syntax:
| rv::transform([](auto&& r){
auto it = ranges::begin(r);
auto next = ranges::next(it);
return std::pair(*it, *next);
})
Demo, using fmt for convenient printing:
int main() {
std::vector<int> v = {1, 1, 2, 2, 3, 3, 4, 4, 5, 5};
auto into_pairs = rv::chunk(2)
| rv::transform([](auto&& r){ return std::pair(r[0], r[1]); });
// prints {(1, 1), (2, 2), (3, 3), (4, 4), (5, 5)}
fmt::print("{}\n", v | into_pairs);
}
It's unclear from the question if you wanted pair<T, T>s or pair<T&, T&>s. The latter is doable by providing explicit types to std::pair rather than relying on class template argument deduction.
C++ is a bit of a moving target - also when it comes to iterators (c++20 has concepts for that...). But would it not be nice to have a lazy solution to the problem. I.e. The tuples get generated on the fly, without casting (see other answers) and without having to write a loop to transform a vector<double> to a vector<tuple<double,double>>?
Now I feel I need a disclaimer because I am not sure this is entirely correct (language lawyers will hopefully point out, if I missed something). But it compiles and produces the expected output. That is something, yes?! Yes.
The idea is to build a pseudo container (which actually is just a facade to an underlying container) with an iterator of its own, producing the desired output type on the fly.
#include <vector>
#include <tuple>
#include <iostream>
#include <iterator>
template <class SourceIter>
struct PairWise {
PairWise() = delete;
PairWise(SourceIter first, SourceIter last)
: first{first}
, last{last}
{
}
using value_type =
typename std::tuple<
typename SourceIter::value_type,
typename SourceIter::value_type
>;
using source_iter = SourceIter;
struct IterState {
PairWise::source_iter first;
PairWise::source_iter last;
PairWise::source_iter current;
IterState(PairWise::source_iter first, PairWise::source_iter last)
: first{first}
, last{last}
, current{first}
{
}
friend bool operator==(const IterState& a, const IterState& b) {
// std::cout << "operator==(a,b)" << std::endl;
return (a.first == b.first)
&& (a.last == b.last)
&& (a.current == b.current);
}
IterState& operator++() {
// std::cout << "operator++()" << std::endl;
if (std::distance(current,last) >= 2) {
current++;
current++;
}
return *this;
}
const PairWise::value_type operator*() const {
// std::cout << "operator*()" << std::endl;
return std::make_tuple(*current, *(current+1));
}
};
using iterator = IterState;
using const_iterator = const IterState;
const_iterator cbegin() const {
return IterState{first,last};
}
const_iterator cend() const {
auto i = IterState{first,last};
i.current = last;
return i;
}
const_iterator begin() const {
// std::cout << "begin()" << std::endl;
return IterState{first,last};
}
const_iterator end() const {
// std::cout << "end()" << std::endl;
auto i = IterState{first,last};
i.current = last;
return i;
}
source_iter first;
source_iter last;
};
std::ostream& operator<<(std::ostream& os, const std::tuple<double,double>& value) {
auto [a,b] = value;
os << "<" << a << "," << b << ">";
return os;
}
template <class Container>
auto pairwise( const Container& container)
-> PairWise<typename Container::const_iterator>
{
return PairWise(container.cbegin(), container.cend());
}
int main( int argc, const char* argv[]) {
using VecF64_t = std::vector<double>;
VecF64_t data{ 1.0, 2.0, 3.0, 4.0, 5.0, 6.0 };
for (const auto x : pairwise(data)) {
std::cout << x << std::endl;
}
return 0;
}
Elements in vector are stored in contiguous memory area, so you can use simple pointer arithmetics to access pair of doubles.
operator++ for iterator should skip 2 doubles at every use.
operator* can return tuple of references to double values, so you can read (pair = *it) or edit values (*it = pair).
struct Cont {
std::vector<double>& v;
Cont(std::vector<double>& v) : v(v) {}
struct Iterator : public std::iterator<std::input_iterator_tag , std::pair<double,double>> {
double* ptrData = nullptr;
Iterator(double* data) : ptrData(data) {}
Iterator& operator++() { ptrData += 2; return *this; }
Iterator operator++(int) { Iterator copy(*this); ptrData += 2; return copy; }
auto operator*() { return std::tie(*ptrData,*(ptrData+1)); }
bool operator!=(const Iterator& other) const { return ptrData != other.ptrData; }
};
auto begin() { return Iterator(v.data()); }
auto end() { return Iterator(v.data()+v.size());}
};
int main() {
std::vector<double> v;
v.resize(4);
Cont c(v);
for (auto it = c.begin(); it != c.end(); it++) {
*it = std::tuple<double,double>(20,30);
}
std::cout << v[0] << std::endl; // 20
std::cout << v[1] << std::endl; // 30
}
Demo
There's not an easy "C++" way to do this that's clean and avoids a copy of the original array. There's always this (make a copy):
vector<double> A; // your original list of points
vector<pair<double,double>> points;
for (size_t i = 0; i < A.size()/2; i+= 2)
{
points[i*2] = pair<double,double>(A[i], A[i+1]);
}
The following would likely work, violates a few standards, and the language lawyers will sue me in court for suggesting it. But if we can assume that the sizeof(XY) is the size of two doubles, has no padding, and expected alignment then cheating with a cast will likely work. This assumes you don't need a std::pair
Non standard stuff ahead
vector<double> A; // your original list of points
struct XY {
double x;
double y;
};
static_assert(sizeof(double)*2 == sizeof(XY));
static_assert(alignof(double) == alignof(XY));
XY* points = reinterpret_cast<XY*>(A.data());
size_t numPoints = A.size()/2;
// iterate
for (size_t i = 0; i < numPoints; i++) {
XY& point = points[i];
cout << point.x << "," << point.y << endl;
}
If you can guarantee that std::vector will always have an even number of entries, you could exploit the fact that an vector of doubles will have the same memory layout as a vector of pairs of doubles. This is kind of a dirty trick though so I wouldn't recommend it if you can avoid it. The good news is that the standard guarantees that vector elements will be contiguous.
inline const std::vector<std::pair<double, double>>& make_dbl_pair(std::vector<double>& v)
{
return reinterpret_cast<std::vector<std::pair<double, double>>&>(v);
}
This will only work for iteration with iterators. The size is likely to be double the number of pairs in the vector because it is still a vector of doubles underneath.
Example:
int main(int argc, char* argv[])
{
std::vector<double> dbl_vec = { 0.0, 1.1, 2.2, 3.3, 4.4, 5.5 };
const std::vector<std::pair<double, double>>& pair_vec = make_dbl_pair(dbl_vec);
for (auto it = pair_vec.begin(); it != pair_vec.end(); ++it) {
std::cout << it->first << ", " << it->second << "\n";
}
std::cout << "Size: " << dbl_vec.size() << "\n";
return 0;
}
Given a two containers: std::list< int > a; and std::list< int > b;, — a.size() == b.size(). Need to sort containers a and b synchronously, i.e. each swap of elements in a should cause a swapping corresponding elements in b (correspondence in sense of positional indices). Assume, that elements in a and b are very heavyweight. I.e. you can't make its copies.
What is the perfect STL-way to do it? How to use std::sort to perform the operation? What to do if a is const?
What I do currently:
#include <iostream>
#include <iomanip>
#include <type_traits>
#include <utility>
#include <iterator>
#include <algorithm>
#include <list>
#include <vector>
#include <cstdlib>
#include <cassert>
template< typename first, typename second >
void
sort_synchronously(first & f, second & s)
{
std::size_t sz = f.size();
assert(sz == s.size());
struct P
{
typename first::iterator pfirst;
typename second::iterator psecond;
bool operator < (P const & p) const { return (*pfirst < *p.pfirst); }
void swap(P & p) noexcept { std::iter_swap(pfirst, p.pfirst); std::swap(pfirst, p.pfirst); std::iter_swap(psecond, p.psecond); std::swap(psecond, p.psecond); }
};
std::vector< P > p;
p.reserve(sz); // O(N) additional memory
auto fi = std::begin(f);
auto si = std::begin(s);
for (std::size_t i = 0; i < sz; ++i) {
p.push_back({fi, si});
++fi;
++si;
}
std::sort(std::begin(p), std::end(p)); // O(N * log N) time
}
int
main()
{
std::list< int > a{5, 4, 3, 2, 1};
std::list< int > b{1, 2, 3, 4, 5};
std::copy(std::cbegin(a), std::cend(a), std::ostream_iterator< int >(std::cout, " ")); std::cout << std::endl;
std::copy(std::cbegin(b), std::cend(b), std::ostream_iterator< int >(std::cout, " ")); std::cout << std::endl;
sort_synchronously(a, b);
std::copy(std::cbegin(a), std::cend(a), std::ostream_iterator< int >(std::cout, " ")); std::cout << std::endl;
std::copy(std::cbegin(b), std::cend(b), std::ostream_iterator< int >(std::cout, " ")); std::cout << std::endl;
return EXIT_SUCCESS;
}
But I can't provide free swap (based on P::swap) function for struct P. Is it unavoidable limitation of the language (I can't define non-lambda function inside function scope, but can define non-template class)?
ADDITIONAL:
I found that presence the swap free function overloading is not the type requirement for std::sort function. Just MoveConstructible and MoveAssignable are. Therefore the code is more appropriate (but still incomplete). There is the really hard issue: swap of elements in range provided to std::sort is (evidently) splitted into series of consistuent operations: T tmp(std::move(lhs)); lhs = std::move(rhs); rhs = std::move(tmp);. Therefore I can't swap (during std::sort) referenced elements of containers itself but only the iterators to them.
One reasonably simple solution is to build a vector v of iterators into your lists, and sort that. Then, the ith element of v points to the elements in the lists that should occupy the ith position in the sorted lists, which you can rebuild. Performance might not be optimal, due to the use of the auxiliary containers, but it's easy to understand.
void ZippedSort(std::list<A>& a, std::list<B>& b) {
using PairOfIts = pair<decltype(a.begin()), decltype(b.begin())>;
vector<PairOfIts> v;
auto i = a.begin();
auto j = b.begin();
for (; i != a.end(); ++i, ++j)
v.push_back(make_pair(i, j));
std::sort(v.begin(), v.end(), [](PairOfIts const& i, PairOfIts const& j) { return *i.first < *j.first; } );
list<A> sortedA;
list<B> sortedB;
for (auto& x : v) {
sortedA.splice(sortedA.end(), a, x.first);
sortedB.splice(sortedB.end(), b, x.second);
}
swap(sortedA, a);
swap(sortedB, b);
}
The perfect STL-way to do it is to fill vector with std::pair and create custom comparator which compares only first element in pair. Then you will have sorted vector of pairs.
The proper way to do it is to create an iterator class with something like std::pair<T1 &, T2 &> as it's value_type. It probably should contain an iterator on each sequence that is to be sorted, and properly propagate operations to them.
In fact, that's exactly what boost::zip_iterator does. I recommend using this with an appropriate comparator; or at least using boost::zip_iterator as an example of how it should work.
OK, done. But it looks like (not too dirty) hack: in T tmp(std::move(lhs)); lhs = std::move(rhs); rhs = std::move(tmp); chain of std::swap implementation I make std::sort algorithm to perform only middle operation (both other are no-op):
#include <iostream>
#include <iomanip>
#include <type_traits>
#include <utility>
#include <iterator>
#include <algorithm>
#include <vector>
#include <forward_list>
#include <cstdlib>
#include <cassert>
template< typename first, typename second >
void
sort_synchronously(first & f, second & s)
{
std::size_t sz = static_cast< std::size_t >(std::distance(std::cbegin(f), std::cend(f)));
assert(sz == static_cast< std::size_t >(std::distance(std::cbegin(s), std::cend(s))));
struct P
{
typename first::iterator pfirst;
typename second::iterator psecond;
bool signal;
bool operator < (P const & p) const { return (*pfirst < *p.pfirst); }
P(typename first::iterator pf, typename second::iterator ps)
: pfirst(pf)
, psecond(ps)
, signal(false)
{ ; }
P(P &&) : signal(true) { ; }
void operator = (P && p) { if (!p.signal) { std::iter_swap(pfirst, p.pfirst); std::iter_swap(psecond, p.psecond); } }
};
std::vector< P > p;
p.reserve(sz);
auto fi = std::begin(f);
auto si = std::begin(s);
for (std::size_t i = 0; i < sz; ++i) {
p.emplace_back(fi, si);
++fi;
++si;
}
std::sort(std::begin(p), std::end(p));
}
int
main()
{
std::forward_list< int > a{5, 4, 3, 2, 1};
std::forward_list< int > b{10, 20, 30, 40, 50};
std::copy(std::cbegin(a), std::cend(a), std::ostream_iterator< int >(std::cout, " ")); std::cout << std::endl;
std::copy(std::cbegin(b), std::cend(b), std::ostream_iterator< int >(std::cout, " ")); std::cout << std::endl;
sort_synchronously(a, b);
std::cout << std::endl;
std::copy(std::cbegin(a), std::cend(a), std::ostream_iterator< int >(std::cout, " ")); std::cout << std::endl;
std::copy(std::cbegin(b), std::cend(b), std::ostream_iterator< int >(std::cout, " ")); std::cout << std::endl;
return EXIT_SUCCESS;
}
I am sure modification for static_assert(std::is_const< first >{}); is evident (just change typename first::iterator to typename first::const_iterator and do std::swap(pfirst, p.pfirst); instead of std::iter_swap(pfirst, p.pfirst);).
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;
}
I have a boost::multi_index_container indexed by an ordered_non_unique key as well as sequenced. When I iterate over the non-unique index, the entries come out in the order they were added to the container rather than their position in the sequence.
How can I set up the non-unique index so that it preserves the insertion order? I tried making a composite_key with ordered_non_unique and sequenced, but since sequenced isn't a keyed index it doesn't compile.
Here's a minimal example (live version here):
#include <boost/multi_index_container.hpp>
#include <boost/multi_index/sequenced_index.hpp>
#include <boost/multi_index/ordered_index.hpp>
#include <boost/multi_index/member.hpp>
#include <iostream>
#include <vector>
using namespace boost::multi_index;
using namespace std;
struct Entry {
int nonUniqueInt;
string somethingExtra;
};
using Container_t = multi_index_container<Entry, indexed_by<
sequenced<>,
ordered_non_unique<
// ***** What can I put here? *****
member<Entry, int, &Entry::nonUniqueInt>
>
>>;
std::vector<Entry> const sampleData{
{1, "first"}, {2, "second"}, {3, "third"}, {3, "fourth"}, {2, "fifth"}, {1, "sixth"}
};
// fillFront should make the sequence LIFO
template <typename T>
void fillFront(T & container) {
for (auto & item : sampleData) {
container.push_front(item);
}
}
// fillBack should make the sequence FIFO
template <typename T>
void fillBack(T & container) {
for (auto & item : sampleData) {
container.push_back(item);
}
}
int main() {
Container_t container;
auto & sequenced = container.get<0>();
auto & ordered = container.get<1>();
fillFront(sequenced);
for(auto & entry : ordered) {
cout << entry.nonUniqueInt << ": " << entry.somethingExtra << endl;
}
cout << endl;
container.clear();
fillBack(sequenced);
for(auto & entry : ordered) {
cout << entry.nonUniqueInt << ": " << entry.somethingExtra << endl;
}
}
// Expected/desired output: Actual output:
// 1: sixth 1: first
// 1: first 1: sixth
// 2: fifth 2: second
// 2: second 2: fifth
// 3: fourth 3: third
// 3: third 3: forth
//
// 1: first 1: first
// 1: sixth 1: sixth
// 2: second 2: second
// 2: fifth 2: fifth
// 3: third 3: third
// 3: forth 3: forth
You want the items to "remain stable" for equivalent keys, in the ordered index.
Boost Multi Index doesn't support that. The "best" you could do is sort the iterators by their appearance in the insertion order index.
Use the random_access index for this.
using Container_t = multi_index_container<Entry, indexed_by<
random_access<>,
ordered_non_unique< member<Entry, int, &Entry::nonUniqueInt> >
>>;
Here's a demo:
int main() {
Container_t container;
auto & sequenced = container.get<0>();
fillFront(sequenced);
stabled_ordered(container, [](Entry const& entry) {
cout << entry.nonUniqueInt << ": " << entry.somethingExtra << endl;
});
cout << endl;
container.clear();
fillBack(sequenced);
stabled_ordered(container, [](Entry const& entry) {
cout << entry.nonUniqueInt << ": " << entry.somethingExtra << endl;
});
}
See it Live On Coliru.
The magic, of course, is stabled_ordered, which is a modified version of std::for_each taking a container and a functor:
template <typename Container, typename F, int RA = 0, int ONU = 1>
F stabled_ordered(Container const& container, F&& f);
The implementation iterates the Order-Non-Unique index (indicated by the ONU template argument) and calls the functor, but in the insertion order (indicated by the RA (random_access) for ranges with equivalent keys:
template <typename Container, typename F, int RA = 0, int ONU = 1>
F stabled_ordered(Container const& container, F&& f)
{
using RAIt = typename Container::template nth_index<RA> ::type::const_iterator;
using ONUIt = typename Container::template nth_index<ONU>::type::const_iterator;
auto& ordered = container.template get<ONU>();
for(ONUIt cursor = ordered.begin(); cursor != ordered.end(); )
{
// get range with equiv. keys
auto key_range = ordered.equal_range(ordered.key_extractor()(*cursor));
cursor = key_range.second;
// project into first index
std::vector<RAIt> v;
for(auto it = key_range.first; it != key_range.second; ++it)
v.push_back(boost::multi_index::project<RA>(container, it));
// put into original order
std::sort(v.begin(), v.end());
for_each(v.begin(), v.end(), [&f](RAIt const& it) { f(*it); });
}
return std::forward<F>(f);
}
Don't be intimidated by the typename .... ::template incantations: these are only there because I wanted to make the algorithm implementation more generic than you probably need :)