Intersection of two `std::map`s - c++

Given that I have two std::maps, say:
map<int, double> A;
map<int, double> B;
I'd like to get the intersection of the two maps, something of the form:
map<int, pair<double,double> > C;
Where the keys are the values in both A and B and the value is a pair of the values from A and B respectively.
Is there a clean way using the standard-library?

#include <map>
#include <utility>
template <typename KeyType, typename LeftValue, typename RightValue>
std::map<KeyType, std::pair<LeftValue, RightValue>>
IntersectMaps(const std::map<KeyType, LeftValue>& left,
const std::map<KeyType, RightValue>& right) {
std::map<KeyType, std::pair<LeftValue, RightValue>> result;
typename std::map<KeyType, LeftValue>::const_iterator il = left.begin();
typename std::map<KeyType, RightValue>::const_iterator ir = right.begin();
while (il != left.end() && ir != right.end()) {
if (il->first < ir->first)
++il;
else if (ir->first < il->first)
++ir;
else {
result.insert(std::make_pair(il->first, std::make_pair(il->second, ir->second)));
++il;
++ir;
}
}
return result;
}
I haven't tested this, or even compiled it... but it should be O(n). Because it's templated it should work with any two maps that share the same key type.

I don't think there is a pure STL way of implementing what you want. Manual implementation should not be too complicated.
Note that std::set_intersection is not a solution. The main reason being that it compares the dereferenced iterators and then copies one of the elements to the output iterator.
While comparison of the full dereferenced iterator includes the associated value (which I understand you do not want to consider as part of the key), can be solved by providing a comparison functor that would only test the key (std::pair<const Key, Value>::first), the problem of the algorithm copying only one of the two values and not composing the solution cannot be tackled externally.
EDIT: A simple linear time implementation of the function:
Note, as #Mark Ransom comments, that this solution adds an extra requirement: the keys must be equality comparable. That is not an issue with his solution here, or similarly in the answer by #Matthiew M here. It would be shameful to modify this algorithm with that fix :)
Another great advantage of #Mark's implementation is that it can compose from maps that store different value types as long as the keys are the same (which seems like an obvious requirement). I wish I would upvote more than once there..
template <typename Key, typename Value>
std::map<Key,std::pair<Value,Value> >
merge_maps( std::map<Key,Value> const & lhs, std::map<Key,Value> const & rhs )
{
typedef typename std::map<Key,Value>::const_iterator input_iterator;
std::map<Key, std::pair<Value,Value> > result;
for ( input_iterator it1 = lhs.begin(), it2 = rhs.begin(),
end1 = lhs.end(), end2 = rhs.end();
it1 != end1 && it2 != end2; )
{
if ( it1->first == it2->first )
{
result[it1->first] = std::make_pair( it1->second, it2->second );
++it1; ++it2;
}
else
{
if ( it1->first < it2->first )
++it1;
else
++it2;
}
}
return result;
}

#include <map>
using namespace std;
typedef int KeyType;
typedef double ValueType;
typedef map< KeyType, ValueType > MyMap;
typedef MyMap::iterator MyMapIter;
typedef MyMap::const_iterator MyMapConstIter;
typedef pair< ValueType, ValueType > ValueTypePair;
typedef map< KeyType, ValueTypePair > MyMapIntersection;
int main() {
MyMap A;
MyMap B;
MyMapIntersection C;
// fill up A, B
for( MyMapConstIter cit = A.begin(); cit != A.end(); ++cit ) {
const KeyType x = cit->first;
MyMapConstIter found = B.find( x );
if( found != B.end() ) {
ValueTypePair valuePair =
ValueTypePair( cit->second, found->second );
C.insert( pair< KeyType, ValueTypePair>( x, valuePair ) );
}
}
}

A (better) solution based on the fact that the maps are sorted. (Shame on me that I overlooked it.) Thanks to David Rodríguez - dribeas for the suggestion.
#include <map>
using namespace std;
typedef int KeyType;
typedef double ValueType;
typedef map< KeyType, ValueType > MyMap;
typedef MyMap::iterator MyMapIter;
typedef MyMap::const_iterator MyMapConstIter;
typedef pair< ValueType, ValueType > ValueTypePair;
typedef map< KeyType, ValueTypePair > MyMapIntersection;
void constructInsert( MyMapIntersection & c, MyMapConstIter const & acit,
MyMapConstIter const & bcit ) {
ValueTypePair valuePair = ValueTypePair( acit->second, bcit->second );
c.insert( pair< KeyType, ValueTypePair>( acit->first, valuePair ) );
}
int main() {
MyMap A;
MyMap B;
MyMapIntersection C;
// fill up A, B
MyMapConstIter acit, bcit;
for( acit = A.begin(), bcit = B.begin();
(acit != A.end()) && (bcit != B.end()); /* Inside loop */ ) {
const KeyType aKey = acit->first;
const KeyType bKey = bcit->first;
if( aKey < bKey ) {
++acit;
}
else if( aKey == bKey ) {
constructInsert( C, acit, bcit );
++acit;
++bcit;
}
else {
++bcit;
}
}
}

Okay, let's get ready to get your hands dirty :)
I'll be using std::mismatch and std::transform
First of all, some types:
typedef std::map<int, double> input_map;
typedef input_map::const_reference const_reference;
typedef input_map::const_iterator const_iterator;
typedef std::pair<const_iterator,const_iterator> const_pair;
typedef std::map<int, std::pair<double,double> > result_map;
Then predicates
bool less(const_reference lhs, const_reference rhs)
{
return lhs.first < rhs.first;
}
result_map::value_type pack(const_reference lhs, const_reference rhs)
{
assert(lhs.first == rhs.first);
return std::make_pair(lhs.first, std::make_pair(lhs.second, rhs.second));
}
Now main:
result_map func(input_map const& m1, input_map const& m2)
{
if (m1.empty() || m2.empty()) { return result_map(); }
// mismatch unfortunately only checks one range
// god do I hate those algorithms sometimes...
if (*(--m1.end()) < *(--m2.end()) { return func(m2, m1); }
const_pair current = std::make_pair(m1.begin(), m2.begin()),
end = std::make_pair(m1.end(), m2.end());
result_map result;
// Infamous middle loop, the check is middle-way in the loop
while(true)
{
const_pair next = std::mismatch(p.first, end.first, p.second, less);
std::transform(current.first, next.first, current.second,
std::inserter(result, result.begin()), pack);
// If any of the iterators reached the end, then the loop will stop
if (next.first == end.first || next.second == end.second) { break; }
// Advance the lesser "next"
if (less(*next.first, *next.second)) { ++next.first; }
else { ++next.second; }
current = next;
}
return result;
}
I find this solution quite elegant... notwithstanding the awkard setup part since we need to ensure that the first range ends up quicker than the second because of mismatch...
Notice that the advance is really stupid, we could loop specifically here until we had *next.first.key == *next.second.key but it would complicate the loop.
I really don't find this better than a handcrafted loop though... consider:
result_map func2(input_map const& lhs, input_map const& rhs)
{
result_map result;
for (const_iterator lit = lhs.begin(), lend = lhs.end(),
rit = rhs.begin(), rend = rhs.end();
lit != lend && rit != rend;)
{
if (lit->first < rit->first) { ++lit; }
else if (rit->first < lit->first) { ++rit; }
else
{
result[lit->first] = std::make_pair(lit->second, rit->second);
++lit, ++rit;
}
}
return result;
}
It's much more compact, probably more efficient... sometimes the functions you're looking are not general enough to be in the STL :)

EDIT: Since I was pretty sure there was a better STL-like solution to this, I figured one out. It's different enough that I'm posting it as a separate answer.
There are a few tricks to this. Firstly, you'd like to use set_intersection, but you have two maps. The solution is a custom comparator and the std::transform algorithm. Someone more familiar with the standard library than me can probably optimize this, but it works. Note that boost::bind would allow you to cut down on the silly helper functions that make this work.
#include <algorithm>
#include <map>
#include <set>
bool myLess(const std::map<int,double>::value_type &v1,
const std::map<int,double>::value_type &v2) {
return v1.first < v2.first;
}
int getKey(const std::map<int,double>::value_type &v) {
return v.first;
}
struct functor {
std::map<int,double> &m1,&m2;
functor(std::map<int,double> &im1, std::map<int,double> &im2) : m1(im1), m2(im2) {}
std::pair<int,std::pair<double,double> > operator() (int x) {
return std::make_pair(x, std::make_pair(m1[x],m2[x]));
}
};
int main() {
std::map<int,double> m1, m2;
m1[0]=0;m1[1]=1; m1[2]=2; m1[3]=3;
m2[1]=11;m2[2]=12;m2[3]=13;m2[4]=14;
std::set<int> keys1,keys2,keys;
//Extract the keys from each map with a transform
std::transform(m1.begin(),m1.end(),std::inserter(keys1,keys1.begin()),getKey);
std::transform(m2.begin(),m2.end(),std::inserter(keys2,keys2.begin()),getKey);
//set_intersection to get the common keys
std::set_intersection(keys1.begin(),keys1.end(),keys2.begin(),keys2.end(),
std::inserter(keys,keys.begin()));
std::map<int, std::pair<double,double> > result;
functor f(m1,m2); //stash our maps into the functor for later use
//transform from the key list to the double-map
std::transform(keys.begin(),keys.end(),std::inserter(result,result.begin()),f);
return 0;
}
Like much of C++, the final use of everything is fairly slick (everything in main()), but the setup is more verbose than we would really like.

The following is a simplification of my previous answer, mostly taking advantage of the fact that set_intersection CAN be used with maps as input, but only if you make the output a set of std::pairs. The result also cuts down intermediates to a single "common keys" list.
#include <algorithm>
#include <map>
#include <set>
struct cK { //This function object does double duty, the two argument version is for
//the set_intersection, the one argument version is for the transform
std::map<int,double> &m1,&m2;
cK(std::map<int,double> &im1, std::map<int,double> &im2) : m1(im1), m2(im2)
std::pair<int,std::pair<double,double> > operator() (std::pair<int,double> v
return std::make_pair(v.first, std::make_pair(m1[v.first],m2[v.first]));
}
bool operator() (std::pair<int,double> v1, std::pair<int,double> v2) {
return v1.first < v2.first;
}
};
int main() {
std::map<int,double> m1, m2;
m1[0]=0;m1[1]=1; m1[2]=2; m1[3]=3;
m2[1]=11;m2[2]=12;m2[3]=13;m2[4]=14;
// Get the subset of map1 that has elements in map2
std::set<std::pair<int,double> > sIntersection;
cK compareKeys(m1,m2);
std::set_intersection(m1.begin(),m1.end(),m2.begin(),m2.end(),
std::inserter(sIntersection,sIntersection.begin()),compareKeys);
// Use a custom transform to produce an output set
std::map<int, std::pair<double,double> > result;
std::transform(sIntersection.begin(),sIntersection.end(),
std::inserter(result,result.begin()), compareKeys);
return 0;
}

Almost a year after... but nevertheless :)
This one is for a set container, but you can easily change it to use a map:
template <class InputIterator, class OutputIterator>
OutputIterator intersect(InputIterator lf, InputIterator ll,
InputIterator rf, InputIterator rl,
OutputIterator result)
{
while(lf != ll && rf != rl)
{
if(*lf < *rf)
++lf;
else if(*lf > *rf)
++rf;
else
{
*result = *lf;
++lf;
++rf;
}
}
return result;
}
Usage:
intersect(set1.begin(), set1.end(),
set2.begin(), set2.end(),
inserter(output_container, output_container.begin()));
set1 and set2 are both set containers whilst output_container can be set, list, array etc..
inserter generates an insert iterator

template<typename K, typename V>
std::map<K, V> UnionMaps(const std::map<K, V> & left, const std::map<K, V> & right)
{
std::map<K, V > result;
typename std::map<K, V>::const_iterator il = left.begin();
typename std::map<K, V>::const_iterator ir = right.begin();
while (il != left.end() && ir != right.end())
{
if ((il->first < ir->first)){
result.insert(make_pair(il->first, il->second));
++il;
}else if ((ir->first < il->first)){
result.insert(make_pair(ir->first, ir->second));
++ir;
}else{
result.insert(make_pair(il->first, il->second+ir->second));//add
++il;
++ir;
}
}
while (il != left.end() ){
result.insert(make_pair(il->first, il->second));
il++;
}
while (ir != right.end() ){
result.insert(make_pair(ir->first, ir->second));
ir++;
}
return result;
}

Related

how to easily check if a std::map and std::unordered_map contains the same elements

I am writing a Google Test unit test, and I want to check if the content of an unordered_map<std::string, std::string> is the same as an std::map<std::string, std::string>
I don't think std::equal will work, as elements in the std::map are sorted according a criterion. The order is not important.
I don't think there is nicer way than just going over all elements of one map and checking if they are present in the other map. If you also check that the amount of elements is the same, you'll know whether the maps are completely the same.
For example:
template<typename K, typename E>
bool maps_equal(const std::map<K, E> &map, const std::unordered_map<K, E> &unordered_map) {
return
map.size() == unordered_map.size() &&
std::all_of(map.cbegin(), map.cend(), [&](const std::pair<const K, E> &item) {
auto iter = unordered_map.find(item.first);
return iter != unordered_map.end() && iter->second == item.second;
});
}
You can create an unordered_map with a map, and then compare two unordered_map. And vice versa.
std::unordered_map<std::string, std::string> m1;
std::map<std::string, std::string> m2;
std::unordered_map<std::string, std::string> m3(m2.begin(), m2.end());
if (m1 == m3) {}
I will ask an obvious question, but it really changes everything:
Is the notion of equality in the map compatible with the notion of equality in the unordered_map?
As an example of incompatible definitions:
struct Point3D { std::int32_t x, y, z };
struct MapLess {
bool operator()(Point3D const& left, Point3D const& right) const {
return std::tie(left.x, left.y) < std::tie(right.x, right.y);
}
};
bool operator==(Point3D const& left, Point3D const& right) {
return std::tie( left.x, left.z)
== std::tie(right.x, right.z);
}
In this (contrived) case, we could have:
map: (1, 2, 3) and (1, 3, 3)
unordered_map: (1, 2, 3) and (1, 2, 4)
and a naive look-up would report that the map is included in the unordered_map which since they both have the same size would lead to the erroneous conclusion that they are equal.
The solution if a canonical notion of equality exists is to verify, after each look-up, that the look-up result is effectively the same as the original.
template <typename M1, typename M2>
bool equal(M1 const& left, M2 const& right) {
if (left.size() != right.size()) { return false; }
for (auto const& e: left) {
auto const it = right.find(e.first);
if (it == right.end()) { return false; }
if (it->first != e.first) { return false; }
if (it->second != e.second) { return false; }
}
return true;
}
Note: this could be rewritten with std::all and a single boolean expression; it's a matter of taste, I prefer breaking it down.
If no canonical notion of equality exists, then a reverse look-up can replace the equality check:
template <typename M1, typename M2>
bool equal(M1 const& left, M2 const& right) {
if (left.size() != right.size()) { return false; }
for (auto e = left.begin(), end = left.end(); e != end; ++e) {
auto const it = right.find(e->first);
if (it != right.end()) { return false; }
if (left.find(it->first) != e) { return false; }
if (it->second != e->second) { return false; }
}
return true;
}
This is of course slightly more expensive.

is there an iterator across unique keys in a std::multimap?

Is there a simple or standard way to have a multimap iterator which iterate across unique keys in a multimap?
i.e. for a set that looks like: {1, "a"}, {1, "lemon"}, {2, "peacock"}, {3, "angel"}
an iterator which would start at {1, "a"} then incrementing would point to {2, "peacock"} and then incrementing again would point to {3, "angel"}?
You can use upper_bound to increment the iterator position instead of ++:
#include <map>
#include <string>
#include <iostream>
using namespace std;
int main()
{
multimap<int,string> mm;
mm.insert(make_pair(1, "a"));
mm.insert(make_pair(1, "lemon"));
mm.insert(make_pair(2, "peacock"));
mm.insert(make_pair(3, "angel"));
for( auto it = mm.begin(), end = mm.end();
it != end;
it = mm.upper_bound(it->first)
)
cout << it->first << ' ' << it->second << endl;
return 0;
}
This results in:
1 a
2 peacock
3 angel
Using upper_bound would result in an easy-to-read loop but each call will perform a binary tree search, resulting in an O(n log n) instead of O(n) traversal. If the difference in efficiency matters, you can structure your traversal like this:
typedef std::multimap<std::string, int> MapType;
MapType container;
for (MapType::iterator it = container.begin(); it != container.end(); ) {
std::string key = it->first;
doSomething(key);
// Advance to next non-duplicate entry.
do {
++it;
} while (it != container.end() && key == it->first);
}
As noted in the selected answer, repeated use of multimap::upper_bound leads to an O(n log n) traversal of the map. Using the external upper_bound function gives you O(n). However, you need to ensure you only compare the key of the map:
std::multimap<int, std::string> myMap = ... ;
const auto compareFirst = [](const std::pair<const int, std::string>& lhs, const std::pair<const int, std::string>& rhs) {
return lhs.first < rhs.first;
};
for(auto it = myMap.begin(); it != myMap.end(); it = std::upper_bound(it, myMap.end(), *it, compareFirst)) {
// Do stuff...
}
The underlying approach is essentially the same as user3701170's solution - i.e linear search - but we put the increment step in the for statement proper, not the loop's body. Aside from putting the increment where it "usually" lives, this also means any continue statements in the loop will behave as expected.
Runnable example
This is a slight improvement over https://stackoverflow.com/a/24212648/895245 with a runnable unit test:
#include <cassert>
#include <map>
#include <vector>
int main() {
// For testing.
auto m = std::multimap<int, int>{
{1, 2},
{1, 3},
{2, 4}
};
std::vector<int> out;
// The algorithm.
auto it = m.begin();
auto end = m.end();
while (it != end) {
auto key = it->first;
// Do what you want to do with the keys.
out.push_back(key);
do {
if (++it == end)
break;
} while (it->first == key);
}
// Assert it worked.
assert(out == std::vector<int>({1, 2}));
}
if you have to pass over all unique keys quickly then you can use std::map instead;
typedef std::map< KeyType, std::list< ValueType > > MapKeyToMultiValue;
Insertion would be more difficult, However you can iterate over all keys without having to bother with duplicate entries. Insertion would look as follows:
void insert_m(MapKeyToMultiValue &map, const KeyType key, const ValueType value )
{
auto it = map.find( key );
if (it == map.end())
{
std::list<ValueType> empty;
std::pair< MapKeyToMultiValue::iterator, bool > ret =
map.insert( MapKeyToMultiValue::value_type( key, empty ) );
it = ret.first;
}
it->second.push_back( value );
}
or you can make that very templated:
template<typename KeyType, typename ValueType,
typename MapType = std::map< KeyType, std::list< ValueType > > >
void insert_multi( MapType &map, const KeyType key, const ValueType value )
{
auto it = map.find( key );
if (it == map.end())
{
std::list<ValueType> empty;
std::pair< typename MapType::iterator, bool > ret =
map.insert( typename MapType::value_type( key, empty ) );
it = ret.first;
}
it->second.push_back( value );
}
The full test program looks as follows:
#include <map>
#include <list>
#include <string>
#include <stdio.h>
typedef std::string KeyType;
typedef int ValueType;
typedef std::map< KeyType, std::list< ValueType > > MapKeyToMultiValue;
void insert_m(MapKeyToMultiValue &map, const KeyType key, const ValueType value )
{
auto it = map.find( key );
if (it == map.end())
{
std::list<ValueType> empty;
std::pair< MapKeyToMultiValue::iterator, bool > ret =
map.insert( MapKeyToMultiValue::value_type( key, empty ) );
it = ret.first;
}
it->second.push_back( value );
}
template<typename KeyType, typename ValueType,
typename MapType = std::map< KeyType, std::list< ValueType > > >
void insert_multi( MapType &map, const KeyType key, const ValueType value )
{
auto it = map.find( key );
if (it == map.end())
{
std::list<ValueType> empty;
std::pair< typename MapType::iterator, bool > ret =
map.insert( typename MapType::value_type( key, empty ) );
it = ret.first;
}
it->second.push_back( value );
}
int main()
{
MapKeyToMultiValue map;
insert_m(map, std::string("aaa"), 1 );
insert_m(map, std::string("aaa"), 2 );
insert_m(map, std::string("bb"), 3 );
insert_m(map, std::string("cc"), 4 );
insert_multi(map, std::string("ddd"), 1 );
insert_multi(map, std::string("ddd"), 2 );
insert_multi(map, std::string("ee"), 3 );
insert_multi(map, std::string("ff"), 4 );
for(auto i = map.begin(); i != map.end(); ++i)
{
printf("%s\n", i->first.c_str() );
}
return 0;
}
Try equal_range:
http://en.cppreference.com/w/cpp/container/multimap/equal_range
That must be an exact match.

Remove overlap from vectors of vectors

What basically I am doing is the set cover problem, removing duplicate from the vectors that has the same numbers. An example:
I have the following vectors of vectors after sorting:
{{1,2,3,4,5},{2,3,7,8},{10,11,12}}
NOW, I would like to remove the occurrence from 2nd vector which is 2,3 and sort again ...
{{1,2,3,4,5},{10,11,12},{7,8}}
I have implemented some code to sort the vectors of vectors but i have problem removing the occurrences from the vector that has less size?
The sort function:
sort(ROWS.begin(),ROWS.end(),VectorsSort());
Thanks for the help.
Pick this apart and take what you need:
#include <algorithm>
#include <vector>
struct binary_search_pred
{
typedef bool result_type;
explicit binary_search_pred(std::vector<int> const& v) : v_(&v) { }
bool operator ()(int const& i) const
{
return std::binary_search(v_->begin(), v_->end(), i);
}
private:
std::vector<int> const* v_;
};
struct size_comparison_desc
{
typedef bool result_type;
typedef std::vector<int> const& arg_t;
bool operator ()(arg_t a, arg_t b) const
{
return b.size() < a.size();
}
};
void set_cover(std::vector<std::vector<int> >& vec)
{
typedef std::vector<std::vector<int> > vec_t;
typedef vec_t::iterator iter_t;
typedef vec_t::const_iterator citer_t;
if (vec.empty() || vec.size() == 1)
return;
for (iter_t v = vec.begin() + 1, v_end = vec.end(); v != v_end; ++v)
for (citer_t p = vec.begin(); p != v; ++p)
v->erase(
std::remove_if(v->begin(), v->end(), binary_search_pred(*p)),
v->end()
);
std::sort(vec.begin(), vec.end(), size_comparison_desc());
}
(Note that set_cover requires that the contained std::vector<int>s given must already be sorted.)
EDIT #1:
As requested in now-deleted comments, a version oriented around std::map<int, std::vector<int>> instead of std::vector<std::vector<int>> (use binary_search_pred from the original code):
#include <algorithm>
#include <map>
#include <vector>
void set_cover(std::map<int, std::vector<int> >& m)
{
typedef std::map<int, std::vector<int> > map_t;
typedef map_t::iterator iter_t;
typedef map_t::const_iterator citer_t;
if (m.empty() || m.size() == 1)
return;
for (iter_t v = ++m.begin(), v_end = m.end(); v != v_end; ++v)
for (citer_t p = m.begin(); p != v; ++p)
v->second.erase(
std::remove_if(
v->second.begin(),
v->second.end(),
binary_search_pred(p->second)
),
v->second.end()
);
}
Note that the map here will always be sorted by its key, never by the contained vector's size (which is what you appear to want). Maybe you want a std::vector<std::pair<int, std::vector<int>>> instead?
EDIT #2:
As requested in now-deleted comments, a version oriented around std::vector<std::pair<int, std::vector<int>>> instead of std::map<int, std::vector<int>> (use binary_search_pred from the original code):
#include <algorithm>
#include <utility>
#include <vector>
struct size_comparison_desc
{
typedef bool result_type;
typedef std::pair<int, std::vector<int> > const& arg_t;
bool operator ()(arg_t a, arg_t b) const
{
return b.second.size() < a.second.size();
}
};
void set_cover(std::vector<std::pair<int, std::vector<int> > >& vec)
{
typedef std::vector<std::pair<int, std::vector<int> > > vec_t;
typedef vec_t::iterator iter_t;
typedef vec_t::const_iterator citer_t;
if (vec.empty() || vec.size() == 1)
return;
for (iter_t v = vec.begin() + 1, v_end = vec.end(); v != v_end; ++v)
for (citer_t p = vec.begin(); p != v; ++p)
v->second.erase(
std::remove_if(
v->second.begin(),
v->second.end(),
binary_search_pred(p->second)
),
v->second.end()
);
std::sort(vec.begin(), vec.end(), size_comparison_desc());
}
You shouldn't need to define a vector sorting predicate. Vector already defines an operator< which is based on std::lexicographical_compare.
Is this what you mean?
std::for_each(rows.begin(), rows.end(), [](std::vector<int>& row) {
row.erase(std::remove_if(row.begin(), row.end(), [](int number) -> bool {
return (number == 2) || (number == 3);
}), row.end());
});

Is there a standard cyclic iterator in C++

Based on the following question: Check if one string is a rotation of other string
I was thinking of making a cyclic iterator type that takes a range, and would be able to solve the above problem like so:
std::string s1 = "abc" ;
std::string s2 = "bca" ;
std::size_t n = 2; // number of cycles
cyclic_iterator it(s2.begin(),s2.end(),n);
cyclic_iterator end;
if (std::search(it, end, s1.begin(),s1.end()) != end)
{
std::cout << "s1 is a rotation of s2" << std::endl;
}
My question, Is there already something like this available? I've checked Boost and STL and neither have an exact implementation.
I've got a simple hand-written (derived from a std::forward_iterator_tag specialised version of std::iterator) one but would rather use an already made/tested implementation.
There is nothing like this in the standard. Cycles don't play well with C++ iterators because a sequence representing the entire cycle would have first == last and hence be the empty sequence.
Possibly you could introduce some state into the iterator, a Boolean flag to represent "not done yet." The flag participates in comparison. Set it true before iterating and to false upon increment/decrement.
But it might just be better to manually write the algorithms you need. Once you've managed to represent the whole cycle, representing an empty sequence might have become impossible.
EDIT: Now I notice that you specified the number of cycles. That makes a big difference.
template< class I >
class cyclic_iterator
/* : public iterator< bidirectional, yadda yadda > */ {
I it, beg, end;
int cnt;
cyclic_iterator( int c, I f, I l )
: it( f ), beg( f ), end( l ), cnt( c ) {}
public:
cyclic_iterator() : it(), beg(), end(), cnt() {}
cyclic_iterator &operator++() {
++ it;
if ( it == end ) {
++ cnt;
it = beg;
}
} // etc for --, post-operations
friend bool operator==
( cyclic_iterator const &lhs, cyclic_iterator const &rhs )
{ return lhs.it == rhs.it && lhs.cnt == rhs.cnt; } // etc for !=
friend pair< cyclic_iterator, cyclic_iterator > cycle_range
( int c, I f, I l ) {//factory function, better style outside this scope
return make_pair( cyclic_iterator( 0, f, l ),
cyclic_iterator( c, f, l ) );
}
};
This should provide some ideas/solutions: 2 renditions, the second is a little lighter in weight. Both tested using a subrange of a vector and a list ...
#include <vector>
template <typename T, typename Container = std::vector<T>, typename Iterator = Container::iterator>
class RingIterator : public std::iterator <std::bidirectional_iterator_tag, T, ptrdiff_t>
{
Container& data;
Iterator cursor;
Iterator begin;
Iterator end;
public:
RingIterator (Container& v) : data(v), cursor(v.begin()), begin(v.begin()), end(v.end()) {}
RingIterator (Container& v, const Iterator& i) : data(v), cursor(i), begin(v.begin()), end(v.end()) {}
RingIterator (Container& v, const Iterator& i, const Iterator& j) : data(v), cursor(i), begin(i), end(j) {}
RingIterator (Container& v, size_t i) : data(v), cursor(v.begin() + i % v.size()), begin(v.begin()), end(v.end()) {}
bool operator == (const RingIterator& x) const
{
return cursor == x.cursor;
}
bool operator != (const RingIterator& x) const
{
return ! (*this == x);
}
reference operator*() const
{
return *cursor;
}
RingIterator& operator++()
{
++cursor;
if (cursor == end)
cursor = begin;
return *this;
}
RingIterator operator++(int)
{
RingIterator ring = *this;
++*this;
return ring;
}
RingIterator& operator--()
{
if (cursor == begin)
cursor = end;
--cursor;
return *this;
}
RingIterator operator--(int)
{
RingIterator ring = *this;
--*this;
return ring;
}
RingIterator insert (const T& x)
{
return RingIterator (data, data.insert (cursor, x));
}
RingIterator erase()
{
return RingIterator (data, data.erase (cursor));
}
};
template <typename T, typename Iterator>
class CyclicIterator : public std::iterator <std::bidirectional_iterator_tag, T, ptrdiff_t>
{
Iterator cursor;
Iterator begin;
Iterator end;
public:
CyclicIterator (const Iterator& i, const Iterator& j) : cursor(i), begin(i), end(j) {}
bool operator == (const CyclicIterator& x) const
{
return cursor == x.cursor;
}
bool operator != (const CyclicIterator& x) const
{
return ! (*this == x);
}
reference operator*() const
{
return *cursor;
}
CyclicIterator& operator++()
{
++cursor;
if (cursor == end)
cursor = begin;
return *this;
}
CyclicIterator operator++(int)
{
CyclicIterator ring = *this;
++*this;
return ring;
}
CyclicIterator& operator--()
{
if (cursor == begin)
cursor = end;
--cursor;
return *this;
}
CyclicIterator operator--(int)
{
CyclicIterator ring = *this;
--*this;
return ring;
}
};
#include <iostream>
#include <iomanip>
#include <list>
enum { CycleSize = 9, ContainerSize };
template <typename cyclicIterator>
void test (cyclicIterator& iterator, size_t mn)
{
int m = mn;
while (m--)
for (int n = mn; n--; ++iterator)
std::cout << std::setw(3) << *iterator << ' ';
--iterator;
m = mn;
while (m--)
for (int n = mn; n--; --iterator)
std::cout << std::setw(3) << *iterator << ' ';
}
template <typename containers>
void load (containers& container)
{
while (container.size() < ContainerSize)
container.push_back (container.size());
}
void main (void)
{
typedef std::vector<int> vContainer;
typedef vContainer::iterator vIterator;
typedef std::list<int> lContainer;
typedef lContainer::iterator lIterator;
vContainer v; load (v);
vIterator vbegin = v.begin() + 1;
RingIterator <int, vContainer, vIterator> vring (v, vbegin, v.end());
CyclicIterator <int, vIterator> vcycle (vbegin, v.end());
lContainer l; load (l);
lIterator lbegin = l.begin(); ++lbegin;
RingIterator <int, lContainer, lIterator> lring (l, lbegin, l.end());
CyclicIterator <int, lIterator> lcycle (lbegin, l.end());
test (vring, CycleSize);
test (vcycle, CycleSize);
test (lring, CycleSize);
test (lcycle, CycleSize);
}
The CGAL library defines Circulators. They are used like this.
template<class Circulator, class T>
bool contains(Circulator c, Circulator d, const T& value) {
if (c != 0) {
do {
if (*c == value)
return true;
} while (++c != d);
}
return false;
}
Note that they look like iterators at first glance but note that the logic (and the structure of the loop) is different than for iterators). if(not empty) do{..}while() instead of while(){...}.
Eric Niebler's ranges-v3 library (on which the upcoming C++20 ranges is based) has ranges::view::cycle. This adapts its source range into an endlessly repeating infinite range. However we require a single repeat which may be easily achieved using ranges::view::concat.
#include <ranges/v3/all.hpp>
int main() {
std::string s1 = "abc";
std::string s2 = "bca";
auto s2s2 = ranges::view::concat(s2, s2);
auto i = std::search(s2s2.begin(), s2s2.end(), s1.begin(), s1.end());
if (i != s2s2.end() && s1.size() == s2.size()) {
std::cout << "s1 is a rotation of s2\n";
}
}
You’re maybe looking for Boost’s Circular Buffer. But if you’ve already checked Boost, it might not be the one you want.
On the other hand, the very idea of cyclic iterator is not compatible to STL container ideology. You should not want cyclic iterator, as the user of this iterator may be surprized by its unusual behavior. Usually in STL you are iterating from the beginning to the end of container. Infinite loop in that case. Because the end is not reachable.
After all, obviously, you are not going to do more than 2 cycles to solve your task. No reason to have special iterator with confusing behavior. That is better to iterate usual linear container twice or may be even less then twice.

Sorting a std::map by value before output & destroy

I'm aware that map is not prepared to be sorted. It's heavily optimized for fast and random key access and actually doesn't support std::sort.
My current problem is that I've a full map<std::string,int> which I'm not going to use anymore. I just need to extract 10 pairs in value(int) order and destroy it.
The best thing, if it was possible, would be to sort it in place and then iterate it 10 times, but that apparently is not a solution.
I'm trying different solutions as going through a multimap<int,string> (to allow duplicate keys), but I'd like to know if there is a more elegant solution, using stl algorithms as much as posible.
EDIT:
I'm using a map because for the 99% of the time, I need it as a map: fast key lookups to increase values. Just need a good way of later extracting in value order when I don't need the map anymore.
Current approach whould be:
std::copy the map(std::string,int) to a vector(pair(std::string,int))
sort the vector
get the first 10 values
destroy vector and map
Maps are stored as a tree sorted in key order. You want the 10 smallest (or largest) integer values, and their keys, right?
In that case, iterate the map and put all the key-value pairs in a vector of pairs (std::vector<std::pair<std::string, int> >). I think you can just use the two-iterator-arg constructor of std::vector for this. Then use std::partial_sort on the vector. Specify a comparator to partial_sort, which compares pairs by just comparing the value int, ignoring the key string. Then you have the 10 pairs you want at the start of the vector, and the rest of the vector contains the remaining pairs in an unspecified order.
Code (untested):
typedef std::pair<std::string, int> mypair;
struct IntCmp {
bool operator()(const mypair &lhs, const mypair &rhs) {
return lhs.second < rhs.second;
}
};
void print10(const std::map<std::string,int> &mymap) {
std::vector<mypair> myvec(mymap.begin(), mymap.end());
assert(myvec.size() >= 10);
std::partial_sort(myvec.begin(), myvec.begin() + 10, myvec.end(), IntCmp());
for (int i = 0; i < 10; ++i) {
std::cout << i << ": " << myvec[i].first
<< "-> " << myvec[i].second << "\n";
}
}
Note that if there are several strings with the same value, either side of the limit of 10, then it's not specified which ones you get. You can control this by having your comparator look at the string too, in cases where the integers are equal.
For iterating by value you could use boost::multi_index. It will looks as follows:
#include <boost/multi_index_container.hpp>
#include <boost/multi_index/member.hpp>
#include <boost/multi_index/ordered_index.hpp>
#include <boost/multi_index/hashed_index.hpp>
using namespace boost::multi_index;
struct X {
X( std::string val_str, int val_int ) : val_str(val_str), val_int(val_int) {};
std::string val_str;
int val_int;
};
typedef multi_index_container<
X,
indexed_by<
hashed_unique< member<X, std::string, &X::val_str> >,
ordered_non_unique< member<X, int, &X::val_int> >
>
> X_map;
void func()
{
X_map data;
data.insert( X("test", 1) );
// ...
// search by val_str
// complexity is equal to O(1) for hashed index (worst cast O(n) ),
// and O(log n) for ordered index
X_map::const_iterator it = data.find( "test" );
// ...
// iterate in order of val_int
size_t N = 0;
for ( X_map::nth_index<1>::type::const_iterator it = data.get<1>().begin(); N < 10 && it != data.get<1>().end(); ++it, ++N ) {
// copy elements somewhere
}
}
You could use any index for iteration ( val_str or val_int ).
May not be the most elegant way, but you can sort them via value in a set as:
#include <map>
#include <set>
#include <iostream>
#include <string>
using namespace std;
struct sortPairSecond
{
bool operator()(const pair<string, int> &lhs, const pair<string, int> &rhs)
{
return lhs.second < rhs.second;
}
};
int main (int argc, char *argv[])
{
cout << "Started...\n";
map<string, int> myMap;
myMap["One"] = 1;
myMap["Ten"] = 10;
myMap["Five"] = 5;
myMap["Zero"] = 0;
myMap["Eight"] = 8;
cout << "Map Order:\n---------------\n";
set<pair<string,int>, sortPairSecond > mySet;
for(map<string, int>::const_iterator it = myMap.begin(); it != myMap.end(); ++it)
{
cout << it->first << " = " << it->second << "\n";
mySet.insert(*it);
}
cout << "\nSet Order:\n--------------\n";
for(set<pair<string, int> >::const_iterator it = mySet.begin(); it != mySet.end(); ++it)
{
cout << it->first << " = " << it->second << "\n";
}
return 1;
}
If you iterate using the map iterator, you will get the items sorted on key as it internally uses balanced binary tree to store the values. So you could just extract the 10 values from it using the iterators. Is that what you want or you want to do something else? Please clarify.
EDIT:
Instead of using the vector and sorting, you can directly use set and pass the comparison function. Then you can extract the top 10 elements. This is my test code:
typedef std::pair<std::string, int> MyPair;
struct MyTestCompare
{
bool operator()(const MyPair& firstPair, const MyPair& secondPair) const
{
return firstPair.second < secondPair.second;
}
};
int main()
{
std::map<std::string, int> m;
m[std::string("1")] = 10;
m[std::string("2")] = 40;
m[std::string("3")] = 30;
m[std::string("4")] = 20;
std::set<MyPair,MyTestCompare> s;
std::map<std::string, int>::iterator iter = m.begin();
std::map<std::string, int>::iterator endIter = m.end();
for(; iter != endIter; ++iter)
{
s.insert(*iter);
}
}
Another possibility is to build a reverse map. For you that would be std::map<int, std::string>. Entries in the reverse map are sorted by their value.
The following is what I have in my tool box for such occasions:
template< typename TK, typename TV, class TP, class TA, typename T1, typename T2 >
inline void asserted_insert(std::map<TK,TV,TP,TA>& m, const T1& k, const T2& v)
{
typedef std::map<TK,TV,TP,TA> map_type;
typedef typename map_type::value_type value_type;
assert( m.insert(value_type(k,v)).second );
}
template< class TMap > struct reverse_map;
template< typename T1, typename T2 > struct reverse_map< std::map<T1,T2> > {
typedef std::map<T2,T1> result_t;
};
template< typename T1, typename T2, class TP1, class TA1, class TP2, class TA2 >
inline void build_reverse_map(const std::map<T1,T2,TP1,TA1>& map, std::map<T2,T1,TP2,TA2>& reverse_map)
{
typedef std::map<T1,T2,TP1,TA1> map_type;
for( typename map_type::const_iterator it=map.begin(),
end=map.end(); it!=end; ++it ) {
asserted_insert( reverse_map, it->second, it->first );
}
}
This code assumes that values are unique, too (and throws an assertion, if this is not the case). If this doesn't apply to your problem, you could easily change the code to use a multi map.