Hi I have a C++ code where there is a struct and list of structs. In my struct, the first element is a string. In list of struct, how do I sort with the first element of the structure so that after sorting all the elements in the list will be arranged alphabetically? please find piece of sample code below. thanks in advance.
struct samplestruct
{
string Name;
int Number
};
samplestruct obj_samplestruct;
vector<samplestruct> List;
obj_samplestruct.Name = "Tom";
obj_samplestruct.Number = 1;
list.push_back(obj_samplestruct);
obj_samplestruct.Name = "Jerry";
obj_samplestruct.Number = 2;
list.push_back(obj_samplestruct);
obj_samplestruct.Name = "Tom";
obj_samplestruct.Number = 3;
list.push_back(obj_samplestruct);
Now in the above code how do I sort as per Name in structure so that in list the members should be arranged alphabatically..
The sort function requires something that can be called with two arguments and returns a bool, this could be a lambda function:
sort( list.begin( ), list.end( ),
[]( const samplestruct& a, const samplestruct&b ){
return a.Name < b.Name;
} );
By default it looks for an operator<, so this would work as well:
bool operator<( const samplestruct& a, const samplestruct&b ){
return a.Name < b.Name;
}
sort( list.begin( ), list.end( ) );
The following code should solve your problem:
struct samplestruct_lessThan
{
bool operator()(samplestruct const & a, samplestruct const & b) const
{
return a.Name < b.Name;
}
};
std::sort(object.begin(), object.end(), samplestruct_lessThan());
Others,
struct samplestruct{
string Name;
int Number;
bool operator<( const samplestruct& a) const {
//just + 'const': maybe patch for the bug of GCC(clang-802.0.42)
return Name < a.Name;
}
};
sort( );
Related
Again me with vectors. I hope I'm not too annoying. I have a struct like this :
struct monster
{
DWORD id;
int x;
int y;
int distance;
int HP;
};
So I created a vector :
std::vector<monster> monsters;
But now I don't know how to search through the vector. I want to find an ID of the monster inside the vector.
DWORD monster = 0xFFFAAA;
it = std::find(bot.monsters.begin(), bot.monsters.end(), currentMonster);
But obviously it doesn't work. I want to iterate only through the .id element of the struct, and I don't know how to do that. Help is greatly appreciated. Thanks !
std::find_if:
it = std::find_if(bot.monsters.begin(), bot.monsters.end(),
boost::bind(&monster::id, _1) == currentMonster);
Or write your own function object if you don't have boost. Would look like this
struct find_id : std::unary_function<monster, bool> {
DWORD id;
find_id(DWORD id):id(id) { }
bool operator()(monster const& m) const {
return m.id == id;
}
};
it = std::find_if(bot.monsters.begin(), bot.monsters.end(),
find_id(currentMonster));
how about:
std::find_if(monsters.begin(),
monsters.end(),
[&cm = currentMonster]
(const monster& m) -> bool { return cm == m; });
You need to write your own search predicate:
struct find_monster
{
DWORD id;
find_monster(DWORD id) : id(id) {}
bool operator () ( const monster& m ) const
{
return m.id == id;
}
};
it = std::find_if( monsters.begin(), monsters.end(), find_monster(monsterID));
Take a look at the std::find template, the third parameter especially:
template<class InputIterator, class EqualityComparable>
InputIterator find(InputIterator first, InputIterator last,
const EqualityComparable& value);
What is this EqualityComparable? Again from the documentation:
A type is EqualityComparable if objects of that type can be
compared for equality using operator==, and if operator== is
an equivalence relation.
Now, your type monster needs to define such an operator. If you don't the compiler generates one for you (as also the default ctor and the dtor) which does a memcmp sort of thing which doesn't work in your case. So, to use std::find first define a comparator function/functor that the algorithm can use to match your currentMonster i.e. something along the lines of:
struct monster {
// members
bool operator==(const monster& l, const monster& r) const
{
return l.id == r.id;
}
};
or put the monsters in a map instead of a vector
or if they must be in a vector create an index map ie map of ID to vector index
This is a complete sample based on the answer of Johannes Schaub (boost version).
#include <algorithm>
#include <boost/bind.hpp>
struct monster
{
DWORD id;
int x;
int y;
int distance;
int HP;
};
int main ()
{
std::vector<monster> monsters;
monster newMonster;
newMonster.id = 1;
newMonster.x = 10;
monsters.push_back ( newMonster );
newMonster.id = 2;
newMonster.x = 20;
monsters.push_back ( newMonster );
newMonster.id = 2;
newMonster.x = 30;
monsters.push_back ( newMonster );
DWORD monsterId = 2;
std::vector< monster >::iterator it = std::find_if ( monsters.begin (), monsters.end (),
boost::bind ( &monster::id, _1 ) == monsterId );
return 0;
}
You can write a function as below:
monster* findMonster(DWORD currentMonster) {
for (auto it = bot.monsters.begin(); it != bot.monsters.end(); it++) {
if (it->id == currentMonster) {
return &(*it);
}
}
return NULL;
}
It returns a pointer to the stored node if it's found in the vector, otherwise returns NULL.
Please note that return it; won't work directly.
Again me with vectors. I hope I'm not too annoying. I have a struct like this :
struct monster
{
DWORD id;
int x;
int y;
int distance;
int HP;
};
So I created a vector :
std::vector<monster> monsters;
But now I don't know how to search through the vector. I want to find an ID of the monster inside the vector.
DWORD monster = 0xFFFAAA;
it = std::find(bot.monsters.begin(), bot.monsters.end(), currentMonster);
But obviously it doesn't work. I want to iterate only through the .id element of the struct, and I don't know how to do that. Help is greatly appreciated. Thanks !
std::find_if:
it = std::find_if(bot.monsters.begin(), bot.monsters.end(),
boost::bind(&monster::id, _1) == currentMonster);
Or write your own function object if you don't have boost. Would look like this
struct find_id : std::unary_function<monster, bool> {
DWORD id;
find_id(DWORD id):id(id) { }
bool operator()(monster const& m) const {
return m.id == id;
}
};
it = std::find_if(bot.monsters.begin(), bot.monsters.end(),
find_id(currentMonster));
how about:
std::find_if(monsters.begin(),
monsters.end(),
[&cm = currentMonster]
(const monster& m) -> bool { return cm == m; });
You need to write your own search predicate:
struct find_monster
{
DWORD id;
find_monster(DWORD id) : id(id) {}
bool operator () ( const monster& m ) const
{
return m.id == id;
}
};
it = std::find_if( monsters.begin(), monsters.end(), find_monster(monsterID));
Take a look at the std::find template, the third parameter especially:
template<class InputIterator, class EqualityComparable>
InputIterator find(InputIterator first, InputIterator last,
const EqualityComparable& value);
What is this EqualityComparable? Again from the documentation:
A type is EqualityComparable if objects of that type can be
compared for equality using operator==, and if operator== is
an equivalence relation.
Now, your type monster needs to define such an operator. If you don't the compiler generates one for you (as also the default ctor and the dtor) which does a memcmp sort of thing which doesn't work in your case. So, to use std::find first define a comparator function/functor that the algorithm can use to match your currentMonster i.e. something along the lines of:
struct monster {
// members
bool operator==(const monster& l, const monster& r) const
{
return l.id == r.id;
}
};
or put the monsters in a map instead of a vector
or if they must be in a vector create an index map ie map of ID to vector index
This is a complete sample based on the answer of Johannes Schaub (boost version).
#include <algorithm>
#include <boost/bind.hpp>
struct monster
{
DWORD id;
int x;
int y;
int distance;
int HP;
};
int main ()
{
std::vector<monster> monsters;
monster newMonster;
newMonster.id = 1;
newMonster.x = 10;
monsters.push_back ( newMonster );
newMonster.id = 2;
newMonster.x = 20;
monsters.push_back ( newMonster );
newMonster.id = 2;
newMonster.x = 30;
monsters.push_back ( newMonster );
DWORD monsterId = 2;
std::vector< monster >::iterator it = std::find_if ( monsters.begin (), monsters.end (),
boost::bind ( &monster::id, _1 ) == monsterId );
return 0;
}
You can write a function as below:
monster* findMonster(DWORD currentMonster) {
for (auto it = bot.monsters.begin(); it != bot.monsters.end(); it++) {
if (it->id == currentMonster) {
return &(*it);
}
}
return NULL;
}
It returns a pointer to the stored node if it's found in the vector, otherwise returns NULL.
Please note that return it; won't work directly.
I have this struct:
struct abc {
int x, y;
char s[20];
};
bool comp(abc a, abc b) {
int n = strlen(a.s), m = strlen(b.s);
for(int i = 0; i < min(n,m); i++)
if(a.s[i] != b.s[i])
return a.s[i] < b.s[i];
return n < m;
}
I want to make a set with this structs sorted by s[] , but I don't know how.
One option is to overload operator< for your structure. Any standard algorithm/container that wants to compare their sort order will use that by default.
bool operator<(abc const & a, abc const & b) {
// your code here
}
Alternatively, you can specify your comparator just for the set:
std::set<abc, bool(*)(abc,abc)> my_set(comp);
This would be a bit more convenient with a function class rather than a function:
struct comp {
bool operator()(abc const & a, abc const & b) {
// your code here
}
};
std::set<abc, comp> my_set;
You need to define the < operator for abc so that stl knows how to compare two instances of abc.
So how do you compare two members of a struct that have 3 fields? Use lexicographical order.
Here is the practical implementation of your example.
struct abc {
int x, y;
char s[20];
const bool operator < ( const abc &r ) const{
return ( x< r.x)
||(( x== r.x) && ( y< r.y))
||(( x== r.x) && ( y== r.y) && strcmp(s,r.s)<0) ;
}
};
Then the set is automatically sorted when you insert in it.
I can't seem to figure out the syntax for finding structs in containers.
I have a multiset of Event structs. I'm trying to find one of these structs by searching on its key. I get the compiler error commented below.
struct Event {
public:
bool operator < ( const Event & rhs ) const {
return ( time < rhs.time );
}
bool operator > ( const Event & rhs ) const {
return ( time > rhs.time );
}
bool operator == ( const Event & rhs ) const {
return ( time == rhs.time );
}
double time;
int eventID;
int hostID;
int s;
};
typedef std::multiset< Event, std::less< Event > > EventPQ;
EventPQ currentEvents;
double oldRecTime = 20.0;
EventPQ::iterator ceItr = currentEvents.find( EventPQ::key_type( oldRecTime ) ); // no matching function call
I've tried a few permutations to no avail. I thought defining the conditional equality operator was going to be enough.
Solution
After correcting my typo (sorry), I now have a solution closest to AraK's, augmented by Soapbox's suggested use of explicit:
struct Event {
explicit Event(double t) : time(t), eventID(), hostID(), s() {}
Event(double t, int eid, int hid, int stype) : time(t), eventID( eid ), hostID( hid ), s(stype) {}
...
};
EventPQ::iterator ceItr = currentEvents.find( EventPQ::key_type( Event(oldRecTime) ) );
I recently discovered that another option would have been to use find_if, discussed here.
Thanks for the help.
You don't have a suitable constructor that accepts double. Just add the following constructor:
Event(double t) : time(t), eventID(/**/), hostIDeventID(/**/), s(/**/)
{ }
Here is how Event would look like:
struct Event {
public:
// Initialize other variables as needed
Event(double t) : time(t), eventID(/**/), hostIDeventID(/**/), s(/**/)
{ }
bool operator < ( const Event & rhs ) const {
return ( time < rhs.time );
}
bool operator > ( const Event & rhs ) const {
return ( time > rhs.time );
}
bool operator == ( const Event & rhs ) const {
return ( time == rhs.time );
}
double time;
int eventID;
int hostID;
int s;
};
// No need for std::less because it is used by default,
// when you define 'operator <' in your class
typedef std::multiset< Event > EventPQ;
EventPQ currentEvents;
double oldRecTime = 20.0;
// You can just pass the double, a temporary object will be created
// for you.
EventPQ::iterator ceItr = currentEvents.find( oldRecTime );
Besides the missing constructor, you don't want to call find() on the iterator ceItr but on currentEvents:
EventPQ::iterator ceItr = currentEvents.find(EventPQ::key_type(oldRecTime));
Note that find() only gives you an iterator to the first match, use equal_range() to get a range of all matches:
std::pair<EventPQ::iterator, EventPQ::iterator> result;
result = currentEvents.find(EventPQ::key_type(oldRecTime));
for(EventPQ::iterator it = result.first; it != result.second; ++it) {
// do stuff
}
You seem to have multiset and multimap confused. Multiset is for when the key and the value are one-and-the-same. Multimap is for when a key and a value are associated, but not the same object.
In this case, Event isn't actually the key. The "time" double appears to be the key. Since the key and the value are not exactly the same, you should use a multimap. Using event as both the key and value doesn't make sense here.
You don't want to construct an event with extra fields you don't need just to search for a given value. Instead, multimap lets you search using the double, which is what you really want. This also eliminates the need for less than operators in the Event class.
Your code would then look something like this:
struct Event {
double time;
int eventID;
int hostID;
int s;
};
typedef std::multimap<double, Event> EventPQ;
EventPQ currentEvents;
double oldRecTime = 20.0;
std::pair<EventPQ::iterator, EventPQ::iterator> results = currentEvents.equal_range(oldRecTime);
for(EventPQ::iterator cur = results.first; cur != results.second; ++cur) {
// do something to *cur
}
Again me with vectors. I hope I'm not too annoying. I have a struct like this :
struct monster
{
DWORD id;
int x;
int y;
int distance;
int HP;
};
So I created a vector :
std::vector<monster> monsters;
But now I don't know how to search through the vector. I want to find an ID of the monster inside the vector.
DWORD monster = 0xFFFAAA;
it = std::find(bot.monsters.begin(), bot.monsters.end(), currentMonster);
But obviously it doesn't work. I want to iterate only through the .id element of the struct, and I don't know how to do that. Help is greatly appreciated. Thanks !
std::find_if:
it = std::find_if(bot.monsters.begin(), bot.monsters.end(),
boost::bind(&monster::id, _1) == currentMonster);
Or write your own function object if you don't have boost. Would look like this
struct find_id : std::unary_function<monster, bool> {
DWORD id;
find_id(DWORD id):id(id) { }
bool operator()(monster const& m) const {
return m.id == id;
}
};
it = std::find_if(bot.monsters.begin(), bot.monsters.end(),
find_id(currentMonster));
how about:
std::find_if(monsters.begin(),
monsters.end(),
[&cm = currentMonster]
(const monster& m) -> bool { return cm == m; });
You need to write your own search predicate:
struct find_monster
{
DWORD id;
find_monster(DWORD id) : id(id) {}
bool operator () ( const monster& m ) const
{
return m.id == id;
}
};
it = std::find_if( monsters.begin(), monsters.end(), find_monster(monsterID));
Take a look at the std::find template, the third parameter especially:
template<class InputIterator, class EqualityComparable>
InputIterator find(InputIterator first, InputIterator last,
const EqualityComparable& value);
What is this EqualityComparable? Again from the documentation:
A type is EqualityComparable if objects of that type can be
compared for equality using operator==, and if operator== is
an equivalence relation.
Now, your type monster needs to define such an operator. If you don't the compiler generates one for you (as also the default ctor and the dtor) which does a memcmp sort of thing which doesn't work in your case. So, to use std::find first define a comparator function/functor that the algorithm can use to match your currentMonster i.e. something along the lines of:
struct monster {
// members
bool operator==(const monster& l, const monster& r) const
{
return l.id == r.id;
}
};
or put the monsters in a map instead of a vector
or if they must be in a vector create an index map ie map of ID to vector index
This is a complete sample based on the answer of Johannes Schaub (boost version).
#include <algorithm>
#include <boost/bind.hpp>
struct monster
{
DWORD id;
int x;
int y;
int distance;
int HP;
};
int main ()
{
std::vector<monster> monsters;
monster newMonster;
newMonster.id = 1;
newMonster.x = 10;
monsters.push_back ( newMonster );
newMonster.id = 2;
newMonster.x = 20;
monsters.push_back ( newMonster );
newMonster.id = 2;
newMonster.x = 30;
monsters.push_back ( newMonster );
DWORD monsterId = 2;
std::vector< monster >::iterator it = std::find_if ( monsters.begin (), monsters.end (),
boost::bind ( &monster::id, _1 ) == monsterId );
return 0;
}
You can write a function as below:
monster* findMonster(DWORD currentMonster) {
for (auto it = bot.monsters.begin(); it != bot.monsters.end(); it++) {
if (it->id == currentMonster) {
return &(*it);
}
}
return NULL;
}
It returns a pointer to the stored node if it's found in the vector, otherwise returns NULL.
Please note that return it; won't work directly.