Comparison Operator for Structure key in C++ Map - c++

#include<bits/stdc++.h>
using namespace std;
struct segment{
int a;
int b;
int c;
bool const operator<(const segment &o) const {
return a < o.a;
}
};
int main()
{
map<segment,int> myMap;
map<segment,int>::iterator it;
struct segment x,y,z;
x.a=2;
x.b=4;
x.c=6;
y.a=2;
y.b=5;
y.c=8;
z.a=2;
z.b=4;
z.c=6;
myMap[y]++;
myMap[z]++;
myMap[x]++;
for( it =myMap.begin(); it != myMap.end(); it++)
cout<<(*it).first.a<<" "<<(*it).second<<endl;
return 0;
}
it gives result as
2 3
but i want it to print
2 1
2 2
In short I want to increment the value of the map if exactly the same struct instance is fed instead of making a new copy

IMO the best way to compare multiple members is using std::tie as it is much harder to mess up:
bool const operator<(const segment &o) const {
return std::tie(a, b, c) < std::tie(o.a, o.b, o.c);
}
Edit: Would just like to add this link to cppreference as the example there is almost exactly your question.

You can change your less operator to:
bool const operator<(const segment &o) const {
return a < o.a || (a == o.a && b < o.b) || (a==o.a && b==o.b && c < o.c) ;
}
This compares the values in the order of a, b, c.
But you can change it anyway you want to compare the structure.

As far as your map is concerned, there is only one unique object here. In terms of the comparison you specified, and the implied equivalence, x == y and y == z. Why? Neither of them is smaller than the other, so, according to STL logic by comparison, they must be equivalent.
Perhaps you're looking for a std::multimap.
Alternatively, if you want to define inequality (and hence implied equivalence) in terms of all the members, you could do something like this:
#include <tuple>
bool const operator<(const segment &o) const {
return std::make_tuple(a, b, c) < std::make_tuple(o.a, o.b, o.c);
}
P.S. You should avoid including stuff from bits, as you're including stuff from the implementation. Instead, try to use stuff like
// See? no bits.
#include <map>

Related

Find if structures with same values exist in vector array

I want to check if there are structures with the same values in the vector array. May someone explain to me how should I do this?
struct mineCoordinate{
int x;
int y;
};
std::vector<mineCoordinate> mines; // vector array
if(std::find(mines.begin(), mines.end(), mineCoordinate{userInputX,userInputY}) != mines.end()) {
//do something if true.}
As you can see I tried std::find function, and I think it should work (
this is the answer to most of these questions like mine). The only condition was to compare the same objects
What seems to be missing from your code is a definition of what it means for two of your mineCoordinate objects to be equal. If you add this
bool operator==(const mineCoordinate& a, const mineCoordinate& b)
{
return a.x == b.x && a.y == b.y;
}
then I think it will work too.
You might have thought that this definition is so obvious that it doesn't need to be explicitly defined, but that is not correct.
If you are using C++20, can you default the == operator:
struct mineCoordinate
{
int x;
int y;
bool operator==(const mineCoordinate&) const = default;
};

Accessing std::map with custom struct as key type causes strange behaviour

I am trying to access std::map with simple custom key, but while most of the time this works, every once in a while, depending on the values given, it will fail to access the mapped value.
Here I baked a test program, that shows the issue in more detail:
#include <map>
#include <cstdint>
#include <cassert>
struct key_type
{
uint32_t a;
uint32_t b;
bool operator<(const key_type& value) const
{
if (value.a < a)
return true;
if (value.b < b)
return true;
return false;
}
key_type(uint32_t a, uint32_t b) : a(a), b(b)
{}
};
std::map<key_type, int*> test;
int get_int(uint32_t a, uint32_t b)
{
if (test.count(key_type(a, b)) == 0)
{
int* r = new int;
assert(r != nullptr);
key_type key = key_type(a, b);
test[key] = r;
assert(test[key] != nullptr);
}
return *test[key_type(a,b)];
}
Now I try to call get_int with two different sets of arguments. The first case works as expected.
int main(int argc, char* argv[])
{
get_int(2, 4);
get_int(3, 4);
get_int(4, 5);
get_int(2, 1);
get_int(120, 1);
return 0;
}
Now if I change the set of values a bit, everything explodes.
int main(int argc, char* argv[])
{
get_int(2, 4);
get_int(3, 4);
get_int(4, 5);
get_int(120, 1);
return 0;
}
The "assert(test[key] != nullptr);" fails. While I can circumvent the actual problem, but I would like to know what happens here under the surface that causes this behaviour?
Your comparison operator does not make much sense. The complement to
(value.a < a)
includes also cases where value.a > a.
If you make the entire body of the comparison operator:
return std::make_pair(a, b) < std::make_pair(value.a, value.b);
even better would be to use std::tie:
return std::tie(a, b) < std::tie(value.a, value.b);
Your operator< does not impose a Strict Weak Ordering™. Therefore, your attempt to use the map is undefined behaviour.
Basically, the operator doesn't actually produce a single ordering that orders all values of that type.
Consider:
bool operator<(const key_type& value) const
{
if (value.a != a)
return value.a < a;
if (value.b != b)
return value.b < b;
return false;
}
Your ordering is loosely weak. Read this article from wikipedia and this one from Wolfram.
I hope you understand the importance of these articles but regardless look at the following case, according to your algorithm
(3,2) < (4,1) returns true
and
(4,1) < (3,2) returns true
the std::map requires strong ordering and the above will cause undefined behaviours.
To fix you must do the following
if a < value.a return true;
if a > value.a return false;
if b < value.b return true;
return false;

Operator for Multiple Points in One Struct

I have a struct that stores two points that should be interchangeable.
struct Edge
{
unsigned short firstIndex;
unsigned short secondIndex;
Edge(unsigned short firstIndex, unsigned short secondIndex) :
firstIndex(firstIndex), secondIndex(secondIndex) {}
};
The operator== method should be as follows (To make them interchangeable)
bool operator == (const Edge& e2) const
{
return
first == e2.first && second == e2.second ||
first == e2.second && second == e2.first;
}
I am looking to create an operator< and operator> method in order to use the struct in a std::map
I have tried the following (using multiplication) but it does not work since there are many cases in which different edges return the same value
bool operator < (const Edge& e2) const
{
return first * second < e2.first * e2.second;
}
The code that I would like to use is the following:
std::map<Edge, unsigned int> edgePoints;
Edge e1(0, 1);
Edge e2(1, 2);
Edge e3(2, 0);
edgePoints[e1] = 2;
edgePoints[e2] = 0;
edgePoints[e3] = 1;
Although the code does not work with my operator< method because 0 * 1 == 2 * 0 so the map returns 2 when I call edgePoints[e3]
Does anyone know of an operator< and operator> method that I could use or even some other way of mapping the edges in order to use the std::map
I would store the indices of the edge in such a way, that the smaller index always is the first index. It looks like the internal representation is irrelevant in your application. You don't need operator== for maps. Here is the example struct:
struct Edge
{
typedef unsigned short Idx; // prefer strong typedef cf boost
Edge(Idx a, Idx b)
:
firstIndex(std::min(a, b)),
secondIndex(std::max(a, b))
{}
Idx firstIndex;
Idx secondIndex;
bool operator<(Edge const & other)
{
if (firstIndex != other.firstIndex)
return firstIndex < other.firstIndex;
return secondIndex < other.secondIndex;
}
}; // Edge
If you want to make your implementation even nicer, some minor suggestions:
Prefer std::array<unsigned short, 2> over separate variables firstIndex and secondIndex. Doing so allows iterating over the indices.
If you are using array, you can shorten the operator< using std::lexicographical_compare.
Consider compairing them as sorted pairs.
bool operator < (const Edge& e2) const
{
if (min(first, second) != min(e2.first, e2.second))
return min(first, second) < min(e2.first, e2.second);
return max(first, second) < max(e2.first, e2.second);
}
Edit: Of course that can be written nicelier with saving mins and maxes as local variables, but the idea should be clear.
Edit: The idea in other answer is better: force your struct to always have first less then second, and it will eliminate all mins and maxes, and make comparation run fast like hell)

Sorting just two elements using STL

Quite often I have two variables foo1 and foo2 which are numeric types. They represent the bounds of something.
A user supplies values for them, but like a recalcitrant musician, not necessarily in the correct order!
So my code is littered with code like
if (foo2 < foo1){
std::swap(foo2, foo1);
}
Of course, this is an idiomatic sort with two elements not necessarily contiguous in memory. Which makes me wonder: is there a STL one-liner for this?
I suggest to take a step back and let the type system do the job for you: introduce a type like Bounds (or Interval) which takes care of the issue. Something like
template <typename T>
class Interval {
public:
Interval( T start, T end ) : m_start( start ), m_end( end ) {
if ( m_start > m_end ) {
std::swap( m_start, m_end );
}
}
const T &start() const { return m_start; }
const T &end() const { return m_end; }
private:
T m_start, m_end;
};
This not only centralizes the swap-to-sort code, it also helps asserting the correct order very early on so that you don't pass around two elements all the time, which means that you don't even need to check the order so often in the first place.
An alternative approach to avoid the issue is to express the boundaries as a pair of 'start value' and 'length' where the 'length' is an unsigned value.
No, but when you notice you wrote the same code twice it's time to write a function for it:
template<typename T, typename P = std::less<T>>
void swap_if(T& a, T& b, P p = P()) {
if (p(a, b)) {
using std::swap;
swap(a, b);
}
}
 
std::minmax returns pair of smallest and largest element. Which you can use with std::tie.
#include <algorithm>
#include <tuple>
#include <iostream>
int main()
{
int a = 7;
int b = 5;
std::tie(a, b) = std::minmax({a,b});
std::cout << a << " " << b; // output: 5 7
}
Note that this isn't the same as the if(a < b) std::swap(a,b); version. For example this doesn't work with move-only elements.
if the data type of your value that you're going to compare is not already in c++. You need to overload the comparison operators.
For example, if you want to compare foo1 and foo2
template <class T>
class Foo {
private:
int value; // value
public:
int GetValue() const {
return value;
}
};
bool operator<(const Foo& lhs, const Foo& rhs) {
return (lhs.GetValue() < rhs.GetValue());
}
If your value is some type of int, or double. Then you can use the std::list<>::sort member function.
For example:
std::list<int> integer_list;
int_list.push_back(1);
int_list.push_back(8);
int_list.push_back(9);
int_list.push_back(7);
int_list.sort();
for(std::list<int>::iterator list_iter = int_list.begin(); list_iter != int_list.end(); list_iter++)
{
std::cout<<*list_iter<<endl;
}

Loop from one integer to another regardless of direction, with minimal overhead

Assume I'm given two unsigned integers:
size_t A, B;
They're loaded out with some random numbers, and A may be larger, equal, or smaller than B. I want to loop from A to B. However, the comparison and increment both depend on which is larger.
for (size_t i = A; i <= B; ++i) //A <= B
for (size_t i = A; i >= B; --i) //A >= B
The obvious brute force solution is to embed these in if statements:
if (A <= B)
{
for (size_t i = A; i <= B; ++i) ...
}
else
{
for (size_t i = A; i >= B; --i) ...
}
Note that I must loop from A to B, so I can't have two intermediate integers and toss A and B into the right slots then have the same comparison and increment. In the "A is larger" case I must decrement, and the opposite must increment.
I'm going to have potentially many nested loops that require this same setup, which means every if/else will have a function call, which I have to pass lots of variables through, or another if/else with another if/else etc.
Is there any tricky shortcut to avoid this without sacrificing much speed? Function pointers and stuff in a tight, often repeated loop sound extremely painful to me. Is there some crazy templates solution?
My mistake, originally misinterpreting the question.
To make an inclusive loop from A to B, you have a tricky situation. You need to loop one past B. So you work out that value prior to your loop. I've used the comma operator inside the for loop, but you can always put it outside for clarity.
int direction = (A < B) ? 1 : -1;
for( size_t i = A, iEnd = B+direction; i != iEnd; i += direction ) {
...
}
If you don't mind modifying A and B, you can do this instead (using A as the loop variable):
for( B+=direction, A != B; A += direction ) {
}
And I had a play around... Don't know what the inlining rules are when it comes to function pointers, or whether this is any faster, but it's an exercise in any case. =)
inline const size_t up( size_t& val ) { return val++; }
inline const size_t down( size_t& val ) { return val--; }
typedef const size_t (*FnIncDec)( size_t& );
inline FnIncDec up_or_down( size_t A, size_t B )
{
return (A <= B) ? up : down;
}
int main( void )
{
size_t A = 4, B = 1;
FnIncDec next = up_or_down( A, B );
for( next(B); A != B; next(A) ) {
std::cout << A << endl;
}
return 0;
}
In response to this:
This won't work for case A = 0, B = UINT_MAX (and vice versa)
That is correct. The problem is that the initial value for i and iEnd become the same due to overflow. To handle that, you would instead use a do->while loop. That removes the initial test, which is redundant because you will always execute the loop body at least once... By removing that first test, you iterate past the terminating condition the first time around.
size_t i = A;
size_t iEnd = B+direction;
do {
// ...
i += direction;
} while( i != iEnd );
size_t const delta = size_t(A < B? 1 : -1);
size_t i = A;
for( ;; )
{
// blah
if( i == B ) { break; }
i += delta;
}
What are you going to do with the iterated value?
If this is going to be some index in an array, you should use the relevant iterator or reverse_iterator class, and implement your algorithms around these. Your code will be more robust, and easier to maintain or evolve. Besides, a lot of tools in the standard library are built using these interfaces.
Actually, even if you don't, you may implement an iterator class which returns its own index.
You can also use a little bit of metaprogramming magic to define how your iterator will behave according to the order of A and B.
Before going further, please consider that this would only work on constant values of A and B.
template <int A,int B>
struct ordered {
static const bool value = A > B ? false: true;
};
template <bool B>
int pre_incr(int &v){
return ++v;
}
template <>
int pre_incr<false>(int &v){
return --v;
}
template <int A, int B>
class const_int_iterator : public iterator<input_iterator_tag, const int>
{
int p;
public:
typedef const_int_iterator<A,B> self_type;
const_int_iterator() : p(A) {}
const_int_iterator(int s) : p(s) {}
const_int_iterator(const self_type& mit) : p(mit.p) {}
self_type& operator++() {pre_incr< ordered<A,B>::value >(p);return *this;}
self_type operator++(int) {self_type tmp(*this); operator++(); return tmp;}
bool operator==(const self_type& rhs) {return p==rhs.p;}
bool operator!=(const self_type& rhs) {return p!=rhs.p;}
const int& operator*() {return p;}
};
template <int A, int B>
class iterator_factory {
public:
typedef const_int_iterator<A,B> iterator_type;
static iterator_type begin(){
return iterator_type();
}
static iterator_type end(){
return iterator_type(B);
}
};
In the code above, I defined a barebone iterator class going accross the values from A to B. There's simple metaprogramming test to determine whether A and B are in ascending order, and pick the correct operator (++ or --) to go through the values.
Finally, I also defined a simple factory class to hold begin and end iterators methods, Using this class let you have only one single point of declaration for your dependent type values A and B (I mean here that you only need to use A and B once for this container, and the iterators generated from there will be depending on these same A and B, thus simplifying code somewhat).
Here I provide a simple test program, outputing values from 20 to 11.
#define A 20
#define B 10
typedef iterator_factory<A,B> factory;
int main(){
auto it = factory::begin();
for (;it != factory::end();it++)
cout << "iterator is : " << *it << endl;
}
There might better ways of doing this with the standard library though.
The issue of using O and UINT_MAX for A and B was brought up. I think it should be possible to handle these cases by overloading the templates using these particular values (left as an exercise for the reader).
size_t A, B;
if (A > B) swap(A,B); // Assuming A <= B, if not, make B to be A
for (size_t i = A; A <= B; ++A) ...