An unordered set of structs - c++

I have been trying to make an unordered_set of structs in c++ but it seems to give me this error-
error: call to implicitly-deleted default constructor
of 'std::__1::hash<coor>'
__compressed_pair_elem(__default_init_tag) {}
I included a == operator, can assist me in making a unordered_set of structures?
#include <iostream>
#include <vector>
#include <unordered_set>
#include <algorithm>
using namespace std;
struct coor{
int x,y;
bool operator==(coor a) const{
if(a.x == x && a.y == y){
return true;
}
else return false;
};
};
int main(){
unordered_set<coor> myset;
}

std::unordered_set uses hashes to identify objects uniquely. It computes the hash using std::hash<> structure. This is fine for primitive or STL containers as they have defined a hash structure for them. But for your case, there isn't a hash structure to generate the hash. The error says it: std::__1::hash<coor>.
To resolve this, we need to implement a std::hash<> for coor.
namespace std {
template<>
struct hash<coor> {
const size_t operator()(const coor& c) const
{
return std::hash<int>()(c.x) ^ std::hash<int>()(c.y);
}
};
}
Now the std::unordered_set has the required hash structure to compute the hash.

Many people use the solution given in the cppreference. Please see here.
But they always open the std namespace and specialize the template for std::hash
Basically that is not necessary.
According to the definition of the std::unordered_set as defined here, we need a hash function and an equal function. And for the hash function we just need an operator().
So, we can make this easily as a part of our struct. We need to overide the ()-operator and implement the hash function. And then we need to override the ==-operator to get the equal function.
Then we add the our struct name as an additional template parameter.
In my humble opinion, it is better to encapsulate the hash and equal functions in our struct, because only this datatype should know, how to calculate values.
Please see here:
#include <unordered_set>
#include <vector>
#include <iostream>
struct coor {
int x{}, y{};
// Hash function
size_t operator()(const coor& c) const { return std::hash<int>()(c.x) ^ std::hash<int>()(c.y); }
// Equal Function
bool operator==(const coor& other) const { return (x == other.x && y == other.y); }
};
int main() {
// Some test values
std::vector<coor> test{ {1,2}, {3,4}, {5,6}, {1,2} };
// Define the unordered set anf fill it with test value
std::unordered_set<coor, coor> myset(test.begin(), test.end());
// Show result. There is no double value 1,2
for (const coor& c : myset) std::cout << c.x << ' ' << c.y << '\n';
return 0;
}
Of course you may also Lambdas as "free" functions for the hash and the equal.
In the following example, we will define 2 Lambdas, one for calculating the hash and one calculating the equal function.
Since the type of the Lambda is only known to the compiler, we use decltype in the template parameter, to inform the compiler, which function "type" we will use in the template.
As an example I defined variable definitions using all 5 available constructors. Please see here for the description.
Please note: You can always and everywhere delete the "myEqual" function, if you add the operator== to the struct as shown above.
Please see the next example below:
#include <unordered_set>
#include <vector>
#include <iostream>
struct coor {
int x{}, y{};
};
constexpr size_t BucketCount = 20u;
int main() {
// Hash function
auto myHash = [](const coor& c) { return std::hash<int>()(c.x) ^ std::hash<int>()(c.y); };
// Equal function
auto myEqual = [](const coor& c1, const coor& c2) { return c1.x == c2.x && c1.y == c2.y; };
// Constructor Number 1
std::unordered_set<coor, decltype(myHash), decltype(myEqual)> myset1(BucketCount, myHash, myEqual);
myset1.insert({ 1,2 }); myset1.insert({ 3,4 }); myset1.insert({ 5,6 }); myset1.insert({ 1,2 });
// Constructor Number 2
std::vector<coor> test{ {1,2}, {3,4}, {5,6}, {1,2} };// Some test values
std::unordered_set<coor, decltype(myHash), decltype(myEqual)> myset2(test.begin(),test.end(), BucketCount, myHash, myEqual);
// Constructor Number 3
std::unordered_set<coor, decltype(myHash), decltype(myEqual)> myset3(myset2);
// Constructor Number 4
std::unordered_set<coor, decltype(myHash), decltype(myEqual)> mysetTemp(myset2);
std::unordered_set<coor, decltype(myHash), decltype(myEqual)> myset4(std::move(mysetTemp));
// Constructor Number 5
std::unordered_set<coor, decltype(myHash), decltype(myEqual)> myset5({ {1,2}, {3,4}, {5,6}, {1,2} }, BucketCount, myHash, myEqual);
// Show result. There is no double value 1,2
for (const coor& c : myset1) std::cout << c.x << ' ' << c.y << '\n'; std::cout << '\n';
for (const coor& c : myset2) std::cout << c.x << ' ' << c.y << '\n'; std::cout << '\n';
for (const coor& c : myset3) std::cout << c.x << ' ' << c.y << '\n'; std::cout << '\n';
for (const coor& c : myset4) std::cout << c.x << ' ' << c.y << '\n'; std::cout << '\n';
for (const coor& c : myset5) std::cout << c.x << ' ' << c.y << '\n'; std::cout << '\n';
return 0;
}
Developed compiled and tested with Microsoft Visual Studio Community 2019, Version 16.8.2
Additionally compiled and tested with gcc10 amnd clang 11
Language: C++17
If you have any questions to the above, then I am happy to answer

Related

C++ function map with varialbles input

In C++, I want to use a map of functions with different type of input or output.
Do to so, I found that using a map with any type could be a way.
But I get several problems. First, I can not use directly the functions in the map.
However, I can use a lambda function to wrap the functions then use these lambda functions in the map.
But, I get a second problem, I still need to cast with the lambda function which is not a variable. This makes a use from a string variable complicated.
Here is a MWE:
#include <any>
#include <functional>
#include <iostream>
#include <map>
#include <string>
void funct0()
{
std::cout << "funct0" << std::endl;
}
void funct1(int p)
{
std::cout << "funct1 " << p << std::endl;
};
int funct2(int p, std::string s)
{
std::cout << "funct2 " << s << std::endl;
return p+1;
};
float funct3(int a, float b)
{
std::cout << "funct3 " << std::endl;
return a +b;
}
auto funct4(int a, float b)
{
std::cout << "funct4 " << std::endl;
std::vector<float> v;
v.push_back(a);
v.push_back(b);
return v;
}
int main()
{
std::map<std::string, std::any> mapFunct;
mapFunct["F0"]= funct0;
// mapFunct["FO"](); // error: no match for call to ‘(std::map<std::__cxx11::basic_string<char>, std::any>::mapped_type {aka std::any}) ()’
mapFunct["F1"]= funct1;
// mapFunct["F1"](12); // error: no match for call to ‘(std::map<std::__cxx11::basic_string<char>, std::any>::mapped_type {aka std::any}) (int)’
// WHY THIS IS NOT WORKING ?
// From this link: https://stackoverflow.com/questions/61969316/is-it-possible-to-put-lambda-expressions-into-a-map-or-list-in-c
auto lambda0 = [](){funct0();};
auto lambda1 = [](int p) { funct1(p); return p; };
auto lambda2 = [](int p, std::string s) { return funct2(p,s); };
auto lambda3 = [](int a, float b){return funct3(a,b);};
auto lambda4 = [](int a, float b){return funct4(a,b);};
std::map<std::string, std::any> mapLambda;
mapLambda["L0"]=lambda0;
mapLambda["L1"]=lambda1;
mapLambda["L2"]=lambda2;
mapLambda["L3"]=lambda3;
mapLambda["L4"]=lambda4;
std::any_cast<decltype(lambda0)>(mapLambda["L0"])();
std::any_cast<decltype(lambda1)>(mapLambda["L1"])(2);
std::cout << std::any_cast<decltype(lambda2)>(mapLambda["L2"])(4, "HELLO") << std::endl;
std::cout << std::any_cast<decltype(lambda3)>(mapLambda["L3"])(3, 4.32) << std::endl ;
auto vec4= std::any_cast<decltype(lambda4)>(mapLambda["L4"])(6, 9.1);
std::cout << "vec4" << vec4[1] << vec4[2] << std::endl ;
std::vector<std::string> inputString;
inputString.push_back("L3(3, 4.32)");
inputString.push_back("L4(6, 9.1)");
// Using a for loop with iterator
for(auto it = std::begin(inputString); it != std::end(inputString); ++it) {
std::cout << *it << "\n";
std::string line=*it;
std::string functionInput = line.substr( 0, line.find("(") );
std::cout << functionInput << std::endl;
// argumentsInput= ;
mapLambda[functionInput](argumentsInput);
}
};
So my question are:
Why my example is working with lambda functions and not the functions ?
How can I make the last part of my example works only from the inputString variable? (ie, knowing the correct casting from the string variable)
What you probably want is something like this:
using CallWrapper = std::function<void(const std::string&)>;
std::map<std::string, CallWrapper> mapLambda;
mapLambda["L0"] = [funct0](const std::string&) { funct0(); };
mapLambda["L1"] = [funct1](const std::string& args) {
int p = ...; // parse the argument from `args`
funct1(p);
};
mapLambda["L2"] = [funct2](const std::string& args) {
// parse the arguments from `args`
int p = ...;
std::string s = ...;
funct2(p, s);
};
Now you can run the loop you envision:
for(const std::string& line : inputString) {
size_t pos = line.find('(');
std::string functionInput = line.substr( 0, pos);
std::string argumentsInput = line.substr(pos);
mapLambda[functionInput](argumentsInput);
}
The hard part, of course, is "parse the arguments from args", left as an exercise for the reader.
std::any_cast needs to cast to constructible types. A standard C++ function is neither a type nor constructible (it's just a group of statements given a name [edit: this isn't technically true, but what's going on under the hood is fairly complicated]), but std::function is. One way to get around this is to assign a standard C++ function to an std::function. Here's an example using a std::map like you were using:
#include <any>
#include <functional>
#include <iostream>
#include <map>
int my_func(int val) { return val + 1; }
std::function<int(int)> f = my_func;
int main() {
auto my_map = std::map<std::string, std::any>();
my_map["func"] = f;
std::cout << std::any_cast<std::function<int(int)>>(my_map["func"])(13) << std::endl; // prints "14"
return 0;
}
Lambdas are constructible types, which is why your code works for lambdas.
To answer your second question: I don't think it's possible. Functions with different signatures are different types, and you have to know what you're casting to. std::function<int(int, string)> and std::function<float(int, float)>, for example, are different types.
Also, the intended purpose of lambdas is to be used once then discarded. If you're going to keep lambdas around for reuse, it's better to simply just use functions.

Counting swaps using std::sort

Is there a portable, minimal-overhead way to count the number of swap operations performed during a std::sort in C++? I would like to do this because I need to compute the sign of the permutation used to sort the list, and I was wondering if there was a way to reuse std::sort for this rather than writing my own sorting function.
I tried to answer real quick by making a wrapper/ custom type to overload std::swap...and then ran into the fact that for super small vectors swap isn't called...following the link in the comments
so attempt 2 added a counter for the move_constructor.
I can't say this is a minimal overhead solution and you're probably better off writing your own sorting function if you need the exact number of swap operations.
#include <iostream>
#include <vector>
#include <algorithm>
#include <random>
struct A{
static int swap_count;
static int move_constructor_count;
int a;
A(int _a): a(_a) {}
bool operator<(const A& other) const{
return this->a < other.a;
}
A(const A&other): a(other.a) {move_constructor_count++;}
};
int A::swap_count = 0;
int A::move_constructor_count = 0;
namespace std{
template<>
void swap(A& lhs, A& rhs) {
A::swap_count++;
std::swap(lhs.a, rhs.a);
}
}
int main() {
std::default_random_engine gen;
std::uniform_int_distribution<int> dis(1,100);
std::vector<A> test;
for(int _=0;_<10;_++) test.emplace_back(dis(gen)); //fill a vector randomly
A::move_constructor_count = 0; // emplace calls move constructor
std::sort(test.begin(), test.end());
std::cout << "after sort1: swap count:" << A::swap_count << " move count: " << A::move_constructor_count << std::endl;
// arbitrary way to fill a large test vector
std::vector<A> test2;
for(int _=0;_<1000;_++) test2.emplace_back(dis(gen)); //fill a vector randomly
A::move_constructor_count = 0;
A::swap_count = 0;
std::sort(test2.begin(), test2.end());
std::cout << "after sort2: swap count:" << A::swap_count << " move count: " << A::move_constructor_count << std::endl;
}
gave me
after sort1: swap count:0 move count: 9
after sort2: swap count:1806 move count: 999

How sort double vector according to changes in first vector?

I would like to implement something like DoubleVector.
In this class I would also like to implement sort method, which sort v1_ and according to changes in v1_ the order in v2_ will also change.
The code is below:
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
class DoubleVector
{
vector<int> v1_;
vector<char> v2_;
public:
void sort()
{
//sort v1_ and also change order in v2_ according to changes in v1_
std::sort(v1_.begin(), v1_.end() /*, lambda ?*/);
}
void add(int value_v1, char value_v2)
{
v1_.push_back(value_v1);
v2_.push_back(value_v2);
}
void print()
{
const auto size = v1_.size();
for (size_t i=0;i<size;++i)
{
cout << v1_[i] << " " << v2_[i] << endl;
}
}
};
int main()
{
DoubleVector dv;
dv.add(6, 'g');
dv.add(2, 'r');
dv.add(3, 'y');
dv.add(4, 'a');
cout << "Before sort:" << endl;
dv.print();
dv.sort();
cout << "After sort:" << endl;
dv.print();//the values in v2_ are in the same order they don't change order according to v1_ changes
return 0;
}
As you can see DoubleVector before sort contains:
6 g
2 r
3 y
4 a
And after sort contains:
2 g
3 r
4 y
6 a
I would like to get:
2 r
3 y
4 a
6 g
So the first vector v1_ has been sorted, but the second still has got the same order and I would like to change order of elements in second v2_ vector according to changes in v1_.
I can write it, but I would like to do it in a fast and clean way, maybe using lambda as third argument in std::sort function? Vectors v1_ and v2_ in class DoubleVector must stay as they are.
Thank you very much.
Make a vector of std::pair<int,char> instead. Since operator < on the pair compares first and decides ties on the second, sorting std::vector<std::pair<int,char>> will produce the exact effect that you want:
vector<pair<int,char>> v;
v.push_back(make_pair(6, 'g'));
v.push_back(make_pair(2, 'r'));
v.push_back(make_pair(3, 'y'));
v.push_back(make_pair(4, 'a'));
sort(v.begin(), v.end());
for (int i = 0 ; i != v.size() ; i++) {
cout << v[i].first << " " << v[i].second << endl;
}
Demo.
You can do something like this:-
vector< pair<int,char> >v;
//do what you want
sort(v.begin(),v.end())
The sort function by default sorts according to first value but you can always define according to which criteria should the sort work
C++ STL - How does the third argument of the STL sort() work?
Try the following.
The way it works is to sort the position key pair based on the int vector value only and then use this ordering to extract values.
#include <iostream>
#include <algorithm>
#include <vector>
class dv
{
std::vector<int> _v1;
std::vector<char> _v2;
std::vector<std::pair<int, int> > _order;
public:
inline bool operator() (const std::pair<int, int>& v1_index_1,
const std::pair<int, int>& v1_index_2) const {
return _v1[v1_index_1.first] < _v1[v1_index_2.first];
}
void sort() {
std::sort(_order.begin(), _order.end(), *this);
}
void add(int value_v1, char value_v2) {
_order.push_back(std::pair<int, int>(_v1.size(), _v2.size()));
_v1.push_back(value_v1);
_v2.push_back(value_v2);
}
void print() {
const auto size(_v1.size());
for (size_t i=0; i<size; ++i) {
std::cout << _v1[_order[i].first]
<< " "
<< _v2[_order[i].second]
<< std::endl;
}
}
};
int main() {
dv dv;
dv.add(6, 'g');
dv.add(2, 'r');
dv.add(3, 'y');
dv.add(4, 'a');
std::cout << "before sort: " << std::endl;
dv.print();
std::cout << "sorting: " << std::endl;
dv.sort();
std::cout << "after sort: " << std::endl;
dv.print();
return 0;
}

Sort a vector using its elements

i need to know how can we sort a vector of user define class using its elements.
Say i have a class called "coordinates" with getX and getY method that return an int value.
I have created and array of vector "vector PointTwoD vcP2D(5);"
class coordinates {
int getX();
int getY();
)
Now the issue,
1) I need to sort the vector "vcP2D" using getX() and sort in asc order
2) Say an user enters the "2" as the x coordinate. And using that info i need to find which vector contains 2
Please advice
This will do:
std::sort(v.begin(), v.end(), [](const coordinates& c, const coordinates& d){ return c.getX() < d.getX(); });
It uses a C++11 Lambda expression as a binary predicate for std::sort.
A short demonstration:
#include <algorithm>
#include <vector>
#include <iostream>
struct coordinates
{
int x;
int y;
};
int main()
{
std::vector<coordinates> v{ {2,3}, {0,0}, {1,5} };
std::sort(v.begin(), v.end(), [](const coordinates& c, const coordinates& d) { return c.x < d.x; });
std::cout << "sorted by x values, values of \"x\": " << v[0].x << " " << v[1].x << " " << v[2].x << "\n";
std::sort(v.begin(), v.end(), [](const coordinates& c, const coordinates& d) { return c.y < d.y; });
std::cout << "sorted by y values, values of \"x\": " << v[0].x << " " << v[1].x << " " << v[2].x << "\n";
}
A demo of how to find an element in the same way:
#include <algorithm>
#include <vector>
#include <iostream>
struct coordinates
{
int x;
int y;
};
int main()
{
std::vector<coordinates> v{ {2,3}, {0,0}, {1,5} };
auto result = std::find_if(v.begin(), v.end(), [](const coordinates& c){ return c.x == 1 && c.y == 5; });
if(result != v.end())
std::cout << "point (1,5) is number " << std::distance(v.begin(), result)+1 << " in the vector.\n";
else
std::cout << "point (1,5) not found.\n";
}
If you are looking to search in the sorted vector, you can use std::binary_search which takes a comparison function (the same as std::sort above). It also does not give an iterator to that element, only a true or false.
You need to define a strict weak order on your elements, either using operator< () or a binary predicate, and then use std::sort().
The easiest approach is to create a less than operator<():
bool operator< (coordinates const& c0, coordinates const& c1) {
// return a suitable result of comparing c0 and c1 such that operator<()
// become a strict weak order
}
With this all you need to do to sort a std::vector<coordinates> is to use std::sort(). To locate a specific object you would use std::lower_bound().

Sort std::vector<myclass> in one line using sort function from STL

Question is about sorting std::vector<myclass> using function sort from STL's algorithms class.
Standard way is : sort(v.begin(), v.end(), &myfunct)
where myfunct is:
bool myfunct( myclass first, myclass second ) {
if (first.value < second.value)
return true;
else return false;
}
Approach above takes more than one line. I am curious how to do it in one line. Is it possible define function that compares myclass objects inside sort function? May be somehow use this (a < b) ? a : b. I remember that there is something like this in C#, but I forgot how is it called. Is it possible to do in C++.
First, you can just return first.value < second.value but this doesn't get rid of the function. In C++2011 you can use a lambda function:
std::sort(begin, end, [](myclass const& f, myclass const& s){ return f.value < s.value; });
Without C++2011 I think you'll need a function object because there isn't anything which projects your class to the value you actually want to compare.
BTW, you definitely want to pass everything but the most trivial objects by reference to your comparison function.
You could use boost::lambda and boost::lambda::bind (with boost lambda placeholders)
std::sort(vec.begin(), vec.end(),
boost::lambda::bind(&A::a, boost::lambda::_1)
<
boost::lambda::bind(&A::a, boost::lambda::_2));
sort passes 2 values to the comparison function so you need to compare those 2 values. The bind part of code just selects variable a from the struct A from each structures being compared (referenced by _1 and _2).
Example code:
#include <iostream>
#include <algorithm>
#include <boost/lambda/lambda.hpp>
#include <boost/lambda/bind.hpp>
#include <boost/array.hpp>
struct A
{
A() : a(0), b(0) {}
int a;
int b;
};
std::ostream & operator<<(std::ostream & os, A & a)
{ return os << a.a << ":" << a.b; }
int main()
{
boost::array<A,5> vec;
std::fill(vec.begin(),vec.end(),A());
vec[0].a = 1;
vec[1].a = 3;
vec[2].a = 4;
vec[3].a = 0;
vec[4].a = 2;
std::for_each(vec.begin(),vec.end(), std::cout << boost::lambda::_1 << ' ');
std::cout << std::endl;
std::sort(vec.begin(), vec.end(),
boost::lambda::bind(&A::a, boost::lambda::_1)
<
boost::lambda::bind(&A::a, boost::lambda::_2));
std::for_each(vec.begin(),vec.end(), std::cout << boost::lambda::_1 << ' ');
std::cout << std::endl;
}
Output:
1:0 3:0 4:0 0:0 2:0
0:0 1:0 2:0 3:0 4:0
why not copy the vector into a set:
std::copy(v.begin(),v.end(),std::inserter(s,s.end()));
Now the elements in the set are sorted in ascending order and use set now.
A one liner call to sort() : sort(my_vector_of_class_object.begin(),my_vector_of_class_object.end(),compare);
Code of a working demo of a "sort vector of class objects" is provided below:
#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
using namespace std;
class my_Class
{
public:
my_Class(int r,int n, int s):rollno(r),name(n),status(s) { }
int getRollno() const { return rollno;}
int getName() const { return name;}
int getStatus() const { return status;}
private:
int rollno;
int name;
int status;
};
bool compare(const my_Class& x, const my_Class& y) {
return x.getRollno() < y.getRollno();
}
int main()
{
vector<my_Class> my_vector_of_class_object;
vector<my_Class>::const_iterator iter;
my_Class s1(10,20,30);
my_Class s2(40,50,60);
my_Class s3(25,85,9);
my_Class s4(1,50,2);
my_Class s5(90,70,90);
my_Class s6(85,85,3);
my_Class s7(20,6,89);
my_Class s8(70,54,22);
my_Class s9(65,22,77);
my_vector_of_class_object.push_back(s1);
my_vector_of_class_object.push_back(s2);
my_vector_of_class_object.push_back(s3);
my_vector_of_class_object.push_back(s4);
my_vector_of_class_object.push_back(s5);
my_vector_of_class_object.push_back(s6);
my_vector_of_class_object.push_back(s7);
my_vector_of_class_object.push_back(s8);
my_vector_of_class_object.push_back(s9);
cout <<"Before vector sort \n";
for(iter=my_vector_of_class_object.begin(); iter!=my_vector_of_class_object.end();++iter)
std::cout << (*iter).getRollno() << '\t' << (*iter).getName() << '\t' << (*iter).getStatus() << '\n';
cout <<" \n\n";
sort(my_vector_of_class_object.begin(),my_vector_of_class_object.end(),compare);
cout <<"After vector sort \n";
for(iter=my_vector_of_class_object.begin(); iter!=my_vector_of_class_object.end();++iter)
std::cout << (*iter).getRollno() << '\t' << (*iter).getName() << '\t' << (*iter).getStatus() << '\n';
cout <<" \n\n";
return 0;
}