Pair equal operator overloading for inserting into set - c++

I am trying to add a pair<int,int> to a set. If a pair shares the same two values as another in the set, it should not be inserted.
Here's my non-working code:
typedef std::pair<int, int> PairInt;
template<>
bool std::operator==(const PairInt& l, const PairInt& r)
{
return (l.first == r.first && l.second == r.second) ||
(l.first == r.second && l.second == r.first);
}
int main()
{
std::set<PairInt> intSet;
intSet.insert(PairInt(1,3));
intSet.insert(PairInt(1,4));
intSet.insert(PairInt(1,4));
intSet.insert(PairInt(4,1));
}
At the moment, the (4,1) pair gets added even though there is already a (1,4) pair. The final contents of the set are:
(1 3)
(1 4)
(4 1)
and I want it to be
(1 3)
(1 4)
I've tried putting breakpoints in the overloaded method, but they never get reached. What have I done wrong?

Sets are based on operator< (an ordering/equivalence relationship), not operator== (which is an equality relationship).
To do the thing that you are trying to do, use a custom comparator:
#include <set>
#include <utility>
#include <cassert>
typedef std::pair<int, int> PairInt;
PairInt normalize(const PairInt& p) {
return p.second < p.first ? PairInt(p.second, p.first) : p;
}
struct Comparator {
bool operator()(const PairInt& l, const PairInt& r) const {
//Compare canonical forms of l and r.
return normalize(l) < normalize(r);
}
};
int main()
{
std::set<PairInt, Comparator> intSet;
intSet.insert(PairInt(1,3));
intSet.insert(PairInt(1,4));
intSet.insert(PairInt(1,4));
intSet.insert(PairInt(4,1));
assert(intSet.size() == 2);
}

You will need to provide a comparison function for seeing of one item is less than the other, not for determining if they are equal. Here is a complete example:
#include <utility>
#include <algorithm>
#include <set>
#include <iostream>
typedef std::pair<int, int> PairInt;
typedef bool Compare(const PairInt &,const PairInt &);
bool compare(const PairInt &l,const PairInt &r)
{
int lfirst = std::min(l.first,l.second);
int rfirst = std::min(r.first,r.second);
if (lfirst<rfirst) return true;
if (rfirst<lfirst) return false;
return std::max(l.first,l.second)<std::max(r.first,r.second);
}
int main()
{
typedef std::set<PairInt,Compare*> IntSet;
IntSet intSet(compare);
intSet.insert(PairInt(1,3));
intSet.insert(PairInt(1,4));
intSet.insert(PairInt(1,4));
intSet.insert(PairInt(4,1));
for (IntSet::const_iterator i=intSet.begin(); i!=intSet.end(); ++i) {
std::cerr << i->first << "," << i->second << "\n";
}
}
Output:
1,3
1,4

The compare should determine if first item is less than the second item. So it should be like this:
namspace std
{
template<>
bool operator < (const PairInt& l, const PairInt& r)
{
//swap only if they're unequal to avoid infinite recursion
if (l.first != l.second)
{
//swap elements, considering your special case
if (l.first == r.second && l.second == r.first)
return l < PairInt(r.second, r.first); //call again!
}
//actual comparison is done here
if ( l.first != r.first )
return l.first < r.first;
else
return l.second < r.second;
}
}
Now it gives the desired output:
1,3
1,4
Have a look at the online demo.
Note that the compare function follows : Strict weak ordering

Related

C++11 Check if at least one element in vector is not in another vector

I wrote the following code in order to check if at least one element in vector is not in another vector.
There are no duplicates in the vectors. Only unique elements
Is there a more elegant way to do it by using the stl?
// Online C++ compiler to run C++ program online
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
bool areVectorsDifferent(vector<int> &a, vector<int> &b){
if(a.size() != b.size()){
return true;
}
std::sort(a.begin(),a.end());
std::sort(b.begin(),b.end());
for(int i = 0; i < a.size();i++){
if(a[i] != b[i]) {
return true;
}
}
return false;
}
int main() {
bool isDifferent = false;
vector<int> a = {1,2,3,5};
vector<int> b = {4,3,2,1};
std::cout << areVectorsDifferent(a,b) << std::endl;
return 0;
}
It depends on your definition of "different", but:
bool areVectorsDifferent(const vector<int> &a, const vector<int> &b){
return a.size() != b.size()
|| std::set<int>{a.cbegin(), a.cend()} != std::set<int>{b.cbegin(), b.cend()};
}
I hope this solves your problem:
using namespace std;
template <typename T>
auto are_different(const vector<T>& lhs, const vector<T>& rhs) -> bool {
return lhs.size() != rhs.size() ||
any_of(cbegin(lhs), cend(lhs), [&rhs](const auto& item) {
return find(cbegin(rhs), cend(rhs), item) == cend(rhs);
});
}

search a structure element in map

i am new to C++(also english).
i want to search {1,2,3} in the map and if it exists , print TRUE on screen
but i can not
my code comes below
can you help me?
#include <iostream>
#include <map>
#include <iterator>
#define PKT_UNIT_MAX_LEN 10000
using namespace std;
struct PKT_UNIT
{
int len;
unsigned int checksum;
unsigned char data[PKT_UNIT_MAX_LEN];
};
int main()
{
map<int,PKT_UNIT> maharan;
maharan.insert(pair<int,PKT_UNIT>(1,{1,2,3}));
map<int,PKT_UNIT> ::iterator it;
it=maharan.begin();
for(it=maharan.begin(); it != maharan.end(); it++ )
{
if (maharan.find(it)!=maharan.end())
{
if (it->second.len==1 && it->second.checksum==2 && it->second.data==3)
cout<<"TRUE"<<endl;
}
return 0;
}
map::find takes something comparable to the key_type, not the mapped_type, and certainly not an iterator. Searching for the value is not what std::map is designed to support. You can instead use the generic searching algorithms.
bool operator==(const PKT_UNIT& lhs, const PKT_UNIT& rhs)
{
return (lhs.len == rhs.len)
&& (lhs.checksum == rhs.checksum)
&& std::equal(lhs.data, lhs.data + lhs.len, rhs.data);
}
int main()
{
PKT_UNIT needle{1,2,3};
std::map<int,PKT_UNIT> maharan;
maharan.insert(pair<int,PKT_UNIT>(1,needle));
auto it = std::find_if(maharan.begin(), maharan.end(), [&needle](auto & item){ return item.second == needle; });
if (it != maharan.end())
{
std::cout << "TRUE";
}
return 0;
}
You should overload the equality operator for PKT_UNIT. Then you should just use std::map::find to find what you are looking for.
bool operator==(const PKT_UNIT& lhs, const PKT_UNIT& rhs)
{
return (lhs.len == rhs.len) &&
(lhs.checksum == rhs.checksum) &&
std::equal(lhs.data,lhs.data + PKT_UNIT_MAX_LEN,rhs.data);
}
The you can do something like this:
PKT_UNIT goal {1,2,3};
for (const auto& e : maharan)
{
if (e.second == goal)
{
std::cout << "TRUE\n";
break;
}
}
Also, as it seems you don't need the key, maybe you want to use std::set and use a search algorithm, or std::unordered_set, in which case you wouldn't need a search algorithm at all.

std::map's find fails to find, but element in map with manual scan

I am using std::map and a list to keep track of windowing over elements and associated scores. When a window is full, I want to pop an element off the windows queue and remove it from the map. Because there can be duplicates, the map keeps track of how many times each element in the window was encountered. I'm also using an ordered map so that I can keep getting the minimum values in a given window.
My problem is that find() is returning end() when it is not expected to.
And when I iterate through the map, I find the element to be present. I don't want to sacrifice the logarithmic complexity of using map.
tl;dr: std::map says an element isn't in the map. A manual scan says it is.
[Edit: Bryan Chen's suggestion fixed the map. Thank you!]
#include <cstdint>
#include <cstdio>
#include <cinttypes>
#include <map>
#include <list>
#include <vector>
#include "util.h"
#include "kmerutil.h"
namespace kpg {
struct elscore_t {
uint64_t el_, score_;
INLINE elscore_t(uint64_t el, uint64_t score): el_(el), score_(score) {
LOG_ASSERT(el == el_);
LOG_ASSERT(score == score_);
}
INLINE elscore_t(): el_(0), score_(0) {}
inline bool operator <(const elscore_t &other) const {
return score_ < other.score_ || el_ < other.el_; // Lexicographic is tie-breaker.
}
inline bool operator ==(const elscore_t &other) const {
return score_ == other.score_ && el_ == other.el_; // Lexicographic is tie-breaker.
}
std::string to_string() const {
return std::to_string(el_) + "," + std::to_string(score_);
}
};
struct esq_t: public std::list<elscore_t> {
};
typedef std::map<elscore_t, unsigned> esmap_t;
class qmap_t {
// I could make this more efficient by using pointers instead of
// elscore_t structs.
// *maybe* TODO
// Could also easily templatify this module for other windowing tasks.
esq_t list_;
#if !NDEBUG
public:
esmap_t map_;
private:
#else
esmap_t map_;
#endif
const size_t wsz_; // window size to keep
public:
void add(const elscore_t &el) {
auto it(map_.upper_bound(el));
if(it->first == el) ++it->second;
else map_.emplace(el, 1);
}
void del(const elscore_t &el) {
auto f(map_.find(el));
if(f == map_.end()) {
LOG_DEBUG("map failed :(\n");
for(f = map_.begin(); f != map_.end(); ++f)
if(f->first == el)
break;
}
LOG_ASSERT(f != map_.end());
if(--f->second <= 0)
map_.erase(f);
}
uint64_t next_value(const uint64_t el, const uint64_t score) {
list_.emplace_back(el, score);
LOG_ASSERT(list_.back().el_ == el);
LOG_ASSERT(list_.back().score_ == score);
add(list_.back());
if(list_.size() > wsz_) {
//fprintf(stderr, "list size: %zu. wsz: %zu\n", list_.size(), wsz_);
//map_.del(list_.front());
del(list_.front());
list_.pop_front();
}
LOG_ASSERT(list_.size() <= wsz_);
return list_.size() == wsz_ ? map_.begin()->first.el_: BF;
// Signal a window that is not filled by 0xFFFFFFFFFFFFFFFF
}
qmap_t(size_t wsz): wsz_(wsz) {
}
void reset() {
list_.clear();
map_.clear();
}
};
}
This is not a valid strict weak ordering:
return score_ < other.score_ || el_ < other.el_;
You have elscore_t(0, 1) < elscore_t(1, 0) and elscore_t(1, 0) < elscore_t(0, 1).
As T.C. pointed out in his answer, your operator< is not correct.
You can use std::tie to do lexicographical comparison
return std::tie(score_, el_) < std::tie(other.score_, other.el_);
Otherwise you can do
if (score_ == other.score_) {
return el_ < other.el_; // use el_ to compare only if score_ are same
}
return score_ < other.score_;

C++ sort pair with respect to two criteria

I have the following vector with pair values:
first 3 second 2
first 1 second 2
first 1 second 1
first 2 second 2
I would like to sort my vector such that the result would be
==========================
first 1 second 2
first 1 second 1
first 2 second 2
first 3 second 2
That means:
sort with respect to the first element.
in case of equality sort with respect to the second element
My code looks like:
#include <utility> // std::pair
#include <iostream> // std::cout
#include <vector>
typedef std::pair<double, double> my_pair;
struct sort_pred
{
bool operator () (const my_pair& left, const my_pair& right)
{
return (left.first < right.first) && (left.second > right.second);
}
};
int main () {
std::vector<my_pair> data;
data.push_back(my_pair(3,2) );
data.push_back(my_pair(1,2) );
data.push_back(my_pair(1,1) );
data.push_back(my_pair(2,2) );
for(auto a: data)
std::cout << "first "<< a.first << " second " << a.second << std::endl;
std::cout << "==========================\n";
std::sort(data.begin(), data.end(), sort_pred());
for(auto a: data)
std::cout << "first "<< a.first << " second " << a.second << std::endl;
return 0;
}
The condition in the sort_pred expressed what I would like to do, but is not correct. I get wrong values.
Any idea how this can be easily solved?
Your comparator isn't quite right, since you want it to return true if either the first check succeeds OR the first are equal and the second check succeeds. You only want to check the seconds if the firsts are equal. So something like this:
struct sort_pred
{
bool operator()(const my_pair& left, const my_pair& right) const
{
if (left.first != right.first) {
return left.first < right.first;
}
return left.second > right.second;
}
};
This can be simplified using the fact that tuples are lexicographically comparable:
struct sort_pred
{
bool operator()(const my_pair& left, const my_pair& right) const
{
return std::tie(left.first, right.second) <
std::tie(right.first, left.second);
}
};
This is possible with a bit of tweaking to your predicate:
struct sort_pred
{
bool operator () (const my_pair& lhs, const my_pair& rhs)
{
return lhs.first<rhs.first ||
(!(rhs.first<lhs.first) && lhs.second>rhs.second);
}
};
Live demo
Your use of && doesn't really make sense. It goes on to evaluate the second element if left.first > right.first, but really you want that to only happen if left.first == right.first.
This should work:
bool operator () (const my_pair& left, const my_pair& right)
{
if (left.first != right.first)
return left.first < right.first;
else
return left.second > right.second;
}
You have to distinguish more cases:
bool operator () (const my_pair& left, const my_pair& right)
{
if (left.first < right.first)
return true;
if (left.first != right.first)
return false;
// when primary criterion is equal:
if (left.second > right.second)
// you want this to sort descending, right?
return true;
// .... other criteria
return false;
}
I think your predicate is wrong ?
If I understand correctly, you want precedence on the first element, and only in case of equality on the second element?
so maybe something like:
struct sort_pred
{
bool operator () (const my_pair& left, const my_pair& right)
{
return (left.first == right.first) ?
(left.second > right.second) :
(left.first < right.first);
}
};
Here you are
#include <iostream>
#include <vector>
#include <algorithm>
#include <utility>
typedef std::pair<double, double> my_pair;
struct sort_pred
{
bool operator ()( const my_pair &left, const my_pair &right ) const
{
return ( left.first < right.first ) ||
( !( right.first < left.first ) && ( right.second < left.second ) );
}
};
int main()
{
std::vector<my_pair> data;
data.push_back( my_pair( 3, 2 ) );
data.push_back( my_pair( 1, 2 ) );
data.push_back( my_pair( 1, 1 ) );
data.push_back( my_pair( 2, 2 ) );
std::stable_sort( data.begin(), data.end(), sort_pred() );
for ( const auto &p : data ) std::cout << p.first << ' ' << p.second << std::endl;
}
The program output is
1 2
1 1
2 2
3 2
You want A to be before B if
A first is less than B first, or
If A first and B first are equal and B second is less than A second
In code that is
(a.first < b.first) or
((a.first == b.first) and
(b.second < a.second))
But this is suboptimal, from a programming point of view: Now you need an additional operator== implemented.
But since a value can only be less, equal or greater than another, you can rewrite that to
(a.first < b.first) or
(not (b.first > a.first) and
(b.second < a.second))

Boost disjoint set

I need to make a disjoint set of the type dataum.
I have all the data in the vector as follows
vector<dataum> S;
S.push_back( dataum(0,0) );
S.push_back( dataum(0,1) );
S.push_back( dataum(0,2) );
.
.
Then I create the disjoint_set
std::vector<int> rank (100);
std::vector<dataum> parent (100);
boost::disjoint_sets<int*,dataum*> ds(&rank[0], &parent[0]);
for( int i=0 ; i<S.size() ; i++ )
{
ds.make_set( S[i] );
}
This seem to not work. What am I missing?
I want to create a disjoint set with custom datatype. In this case dataum. Initially each of my dataums should be in different sets.
The documentation states that
Rank must be a model of ReadWritePropertyMap with an integer value type and a key type equal to the set's element type.
Parent must be a model of ReadWritePropertyMap and the key and value type the same as the set's element type.
At your previous question I posted the following sample code in a comment:
After looking at the (new for me) disjoint_set_* classes, I don't think that they afford iterating members of sets. They act like unidirectional mapping from element to set representative. In case it helps you: http://paste.ubuntu.com/8881626 – sehe 9 hours ago
Here it is, reworked for an imagined dataum type:
struct dataum {
int x,y;
bool operator< (const dataum& o) const { return tie(x,y) < tie(o.x,o.y); }
bool operator==(const dataum& o) const { return tie(x,y) == tie(o.x,o.y); }
bool operator!=(const dataum& o) const { return tie(x,y) != tie(o.x,o.y); }
};
Here's how I can see a disjoint_set declaration for it:
std::map<dataum,int> rank;
std::map<dataum,dataum> parent;
boost::disjoint_sets<
associative_property_map<std::map<dataum,int>>,
associative_property_map<std::map<dataum,dataum>> > ds(
make_assoc_property_map(rank),
make_assoc_property_map(parent));
The mechanics of this are to be found in the documentation for Boost PropertyMap, which is a very powerful generic data structure abstraction layer, mostly used with Boost Graph Library. It's wildly powerful, but I can't say it's user friendly.
Here's the full demo Live On Coliru¹
#include <boost/pending/disjoint_sets.hpp>
#include <boost/property_map/property_map.hpp>
#include <boost/tuple/tuple_comparison.hpp>
#include <iostream>
#include <map>
#include <cassert>
using namespace boost;
struct dataum {
int x,y;
bool operator< (const dataum& o) const { return tie(x,y) < tie(o.x,o.y); }
bool operator==(const dataum& o) const { return tie(x,y) == tie(o.x,o.y); }
bool operator!=(const dataum& o) const { return tie(x,y) != tie(o.x,o.y); }
};
int main() {
std::vector<dataum> S { {0,0}, {0,1}, {0,2} };
std::map<dataum,int> rank;
std::map<dataum,dataum> parent;
boost::disjoint_sets<
associative_property_map<std::map<dataum,int>>,
associative_property_map<std::map<dataum,dataum>> > ds(
make_assoc_property_map(rank),
make_assoc_property_map(parent));
for(auto i=0ul; i<S.size(); i++)
ds.make_set(S[i]);
assert((ds.count_sets(S.begin(), S.end()) == 3));
assert((ds.find_set(dataum{0,2}) == dataum{0,2}));
assert((ds.find_set(dataum{0,1}) == dataum{0,1}));
ds.union_set(dataum{0,2},dataum{0,1});
assert((ds.count_sets(S.begin(), S.end()) == 2));
assert((ds.find_set(dataum{0,2}) == dataum{0,1}));
assert((ds.find_set(dataum{0,1}) == dataum{0,1}));
std::cout << "done";
}
¹ Coliru still not cooperating