Sort a vector of objects by an object's attribute
You should implement an operator<
on cat so that cats can be sorted:
class cat {
public:
int age;
bool operator< (const cat &other) const {
return age < other.age;
}
};
You can then include the "algorithm" header and use std::sort
on your array:
vector< cat > catSorter::SortCatsByAge(){
vector< cat > cats_copy = cats;
std::sort(cats_copy.begin(), cats_copy.end());
return cats_copy;
}
Sorting a vector of objects by a property of the object
There are several different objects and several different properties that could it be sorted by.
While the solution Erik posted is correct, this statement leads me to think that it's impractical at best if you are in fact planning to sort by multiple public data members of multiple classes in multiple ways in the same program, as each sorting method will require its own functor type.
I recommend the following abstraction:
#include <functional>
template<typename C, typename M, template<typename> class Pred = std::less>
struct member_comparer : std::binary_function<C, C, bool> {
explicit member_comparer(M C::*ptr) : ptr_{ptr} { }
bool operator ()(C const& lhs, C const& rhs) const {
return Pred<M>{}(lhs.*ptr_, rhs.*ptr_);
}
private:
M C::*ptr_;
};
template<template<typename> class Pred = std::less, typename C, typename M>
member_comparer<C, M, Pred> make_member_comparer(M C::*ptr) {
return member_comparer<C, M, Pred>{ptr};
}
Usage would look like:
#include <algorithm>
#include <string>
#include <vector>
struct MyClass {
int i;
std::string s;
MyClass(int i_, std::string const& s_) : i{i_}, s{s_} { }
};
int main() {
std::vector<MyClass> vec;
vec.emplace_back(2, "two");
vec.emplace_back(8, "eight");
// sort by i, ascending
std::sort(vec.begin(), vec.end(), make_member_comparer(&MyClass::i));
// sort by s, ascending
std::sort(vec.begin(), vec.end(), make_member_comparer(&MyClass::s));
// sort by s, descending
std::sort(vec.begin(), vec.end(), make_member_comparer<std::greater>(&MyClass::s));
}
This will work for any type with public data members, and will save a lot of typing if you need to sort your classes more than a couple of different ways.
Here is a variation that works with public member functions instead of public data members:
#include <functional>
template<typename C, typename M, template<typename> class Pred = std::less>
struct method_comparer : std::binary_function<C, C, bool> {
explicit method_comparer(M (C::*ptr)() const) : ptr_{ptr} { }
bool operator ()(C const& lhs, C const& rhs) const {
return Pred<M>{}((lhs.*ptr_)(), (rhs.*ptr_)());
}
private:
M (C::*ptr_)() const;
};
template<template<typename> class Pred = std::less, typename C, typename M>
method_comparer<C, M, Pred> make_method_comparer(M (C::*ptr)() const) {
return method_comparer<C, M, Pred>{ptr};
}
With usage like:
#include <algorithm>
#include <string>
#include <vector>
class MyClass {
int i_;
std::string s_;
public:
MyClass(int i, std::string const& s) : i_{i}, s_{s} { }
int i() const { return i_; }
std::string const& s() const { return s_; }
};
int main() {
std::vector<MyClass> vec;
vec.emplace_back(2, "two");
vec.emplace_back(8, "eight");
// sort by i(), ascending
std::sort(vec.begin(), vec.end(), make_method_comparer(&MyClass::i));
// sort by s(), ascending
std::sort(vec.begin(), vec.end(), make_method_comparer(&MyClass::s));
// sort by s(), descending
std::sort(vec.begin(), vec.end(), make_method_comparer<std::greater>(&MyClass::s));
}
Sorting a vector of custom objects
A simple example using std::sort
struct MyStruct
{
int key;
std::string stringValue;
MyStruct(int k, const std::string& s) : key(k), stringValue(s) {}
};
struct less_than_key
{
inline bool operator() (const MyStruct& struct1, const MyStruct& struct2)
{
return (struct1.key < struct2.key);
}
};
std::vector < MyStruct > vec;
vec.push_back(MyStruct(4, "test"));
vec.push_back(MyStruct(3, "a"));
vec.push_back(MyStruct(2, "is"));
vec.push_back(MyStruct(1, "this"));
std::sort(vec.begin(), vec.end(), less_than_key());
Edit: As Kirill V. Lyadvinsky pointed out, instead of supplying a sort predicate, you can implement the operator<
for MyStruct
:
struct MyStruct
{
int key;
std::string stringValue;
MyStruct(int k, const std::string& s) : key(k), stringValue(s) {}
bool operator < (const MyStruct& str) const
{
return (key < str.key);
}
};
Using this method means you can simply sort the vector as follows:
std::sort(vec.begin(), vec.end());
Edit2: As Kappa suggests you can also sort the vector in the descending order by overloading a >
operator and changing call of sort a bit:
struct MyStruct
{
int key;
std::string stringValue;
MyStruct(int k, const std::string& s) : key(k), stringValue(s) {}
bool operator > (const MyStruct& str) const
{
return (key > str.key);
}
};
And you should call sort as:
std::sort(vec.begin(), vec.end(),greater<MyStruct>());
Sorting vector of objects by object's variable
You can try something like that:
for (int i = 0; i < myVector.size(); i++)
{
for (int j = 0; j < myVector.size() - 1; j++)
{
if (myVector[j].x < myVector[j + 1].x)
{
std::swap(myVector[j], myVector[j + 1]);
}
else if (myVector[j].x == myVector[j + 1].x)
{
if (myVector[j].y < myVector[j + 1].y)
std::swap(myVector[j], myVector[j + 1]);
}
}
}
sorting a vector of classes based on a variable in the class
If you have a vector of your class object
std::vector<MyClass> objs;
And the variable to sort by is
MyClass.value
Then you can
std::sort(objs.begin(),
objs.end(),
[](const MyClass& lhs, const MyClass& rhs)
{
return lhs.value < rhs.value;
});
Sort vector of class objects based on some member variable
You can implement the comparison operators.
bool Record::operator<(const Record& rhs) {
return score < rhs.score;
}
bool Record::operator<=(const Record& rhs) {
return score <= rhs.score;
}
Note, if you define <
and <=
, you should also probably define the other comparison operators >
, >=
, ==
, and !=
. You should also enforce a strict weak ordering (e.g. a < b
, b < c
implies a < c
).
Then to sort descending, you could use the following...
std::sort(records.begin(), records.end(),
[] (const Record& lhs, const Record& rhs) -> bool { return lhs > rhs; });
C++11 sort collection of custom objects by several properties
Just change the comparator. Suppose you want to order by year, then by month, then by amount, then:
std::sort( values.begin(), values.end(), [ ]( const MyStruct& lhs, const MyStruct& rhs )
{
return std::tie(lhs.year, lhs.month, lhs.amount) <
std::tie(rhs.year, rhs.month, rhs.amount);
});
std::tuple
's operator<
does a lexicographical comparison, so there's no need to roll your own (and risk getting it wrong). To do a descending order for an attribute, just swap lhs
and rhs
for that attribute.
std::sort on a vector of Objects containing Objects* pointers
Yes, the pointers will still point to the same instance. But that may not be what you actually want. When you call std::sort
on a vector, it does not change the location of instances (that's not even a thing you can do in C++). It swaps their values with each other. This is probably better explained with a simplified example. Take this struct:
struct Foo
{
int x;
Foo* buddy;
};
bool operator<(Foo const& lhs, Foo const& rhs)
{
return lhs.x < rhs.x;
}
Now, lets say I make a vector of these, with decreasing x values, and each one having a pointer to the one that comes after it (and the last having a pointer to the first):
std::vector<Foo> vec(5);
for (int i = 0; i < 5; ++i)
{
vec[i].x = 4 - i;
vec[i].buddy = &vec[(i + 1) % 5];
}
Now, if I sort this vector, it is essentially going to reverse. But the instances themselves don't change their location. Instead, their values change such that the first one has the lowest x
value, and it increases from there. Now, the pointer member changes along with the x
value.
So take, for example, vec[0]
, which had an x
value of 4, and a pointer to vec[1]
(which has an x
value of 3). After the sort, those values will end up in the last element, vec[4]
. So vec[4]
will have an x
value of 4, and a pointer to vec[1]
(which, after the sort, has an x
value of 1).
So, before the sort, the element with the x
value 4, had a pointer to the element with an x
value of 3. After the sort, the element with the x
value of 4 has a pointer to the element with the x
value of 1. I doubt this is what you wanted.
Since you are interested in the identity of the instances, not just their values, you should probably be using something like std::vector<std::unique_ptr<dockPose>>
. For my Foo
example, I could do something like this:
std::vector<std::unique_ptr<Foo>> vec;
for (int i = 0; i < 5; ++i)
vec.emplace_back(new Foo);
for (int i = 0; i < 5; ++i)
{
vec[i]->x = 4 - i;
vec[i]->buddy = vec[(i + 1) % 5].get();
}
Note that when you do this, you need to use a different comparison function. One which compares the dereferenced pointers, rather than the pointers themselves.
c++ std::sort on vector of objects by attribute
Try this:
[] (const finalwords& x, const finalwords& y)
{
if (x.isPopular != y.isPopular) return x.isPopular;
else if (x.isFirstSearch != y.isFirstSearch) return x.isFirstSearch;
else return false;
}
DEMO
Related Topics
Can a Variable Be Declared Both Static and Extern
How to Implement a Map with Different Data Types as Values
Does New Line Character Also Flush the Buffer
How to Convert from Lpctstr to Std::String
When a Float Variable Goes Out of the Float Limits, What Happens
Why Should I Avoid MACros in C++
Memory Allocation and Deallocation Across Dll Boundaries
How Can Cstring Be Passed to Format String %S
Implementation of Permutation, Combinations and Powerset in C++
How Does a Sentinel Node Offer Benefits Over Null
How Disastrous Is Integer Overflow in C++
How to Add Zlib to an Existing Qt Installation
Portable End of Line (Newline)