I'm trying to figure out the best way to sort an array under multiple criteria. I want to sort an array, then sort a subset of that array if they were equal under the first criteria.
Example:
Say we have the data: { ("cat", 2), ("dog", 4), ("cat", 1), ("dog", 3) }
We sort this first according to alphabetical order of the string:
{ ("cat", 2), ("cat", 1), ("dog", 4), ("dog", 3) }
Then we sort the two subsets (set of cats and the set of dogs) in increasing order of their numbers:
{ ("cat", 1), ("cat", 2), ("dog", 3), ("dog", 4) }
Also, I'm using a recursive quicksort method that has the following header:
void quickSort(vector<Type*>, int left, int right)
where left and right are the bounding indices by which the vector should be sorted.
Should I add code to the sorting method itself or should i call the sorting method again somehow?
Generally, you want a custom comparator to sort with.
struct Foo {
std::string name;
int count;
struct Less {
bool operator()(const Foo &lhs, const Foo &rhs) const {
if ((int c = lhs.name.compare(rhs.name)) != 0)
return c < 0;
return lhs.count < rhs.count;
}
};
};
std::vector<Foo> foos;
// ...
std::sort(foos.begin(), foos.end(), Foo::Less());
If you can't just use a single custom operator, you can use a stable sort.
As pointed out by Mark, std::sort is not a stable sort. Instead you would need to use std::stable_sort.
You want to sort them independently in order of increasing importance. So, you sort by numbers and then by the string.
struct Foo {
std::string name;
int count;
struct NameLess {
bool operator()(const Foo &lhs, const Foo &rhs) const {
return lhs.name.compare(rhs.name) < 0;
}
};
struct CountLess {
bool operator()(const Foo &lhs, const Foo &rhs) const {
return lhs.count < rhs.count;
}
};
};
std::vector<Foo> foos;
// ...
std::stable_sort(foos.begin(), foos.end(), Foo::CountLess());
std::stable_sort(foos.begin(), foos.end(), Foo::NameLess());
You would prefer the first obviously, but the latter can come in handy for keeping combinatorial and/or run-time configurable algorithms simplistic.
For reference:
cplusplus.com C++ : Reference : STL Algorithms : stable_sort
cplusplus.com C++ : Reference : STL Algorithms : sort
If you store your data as a vector<pair<string, int> > then you can just use std::sort(vec.begin(), vec.end()); and it will just work because pair's operator< will already use both parts of the object to do the sorting.
you could overload your < operator then you could use vector.unique() and then vector.sort()
In your case you need a custom comparator cause you are mixing data Types you couldn't compare your standart comparator could only compare same data Types and doesn't know with which criteria you would sort.
Related
In my homework my task is to create the FooCl class for these:
double d[] = {1.3, 0.7, 2.4, 1.5, 6.2, 5.7, 8.6, 9.1};
FooCl<double> itemsD(d, sizeof(d) / sizeof(d[0]));
std::string s[] = {"C++", "Haskell", "Python", "Java"};
FooCl<std::string> itemsS(s, sizeof(s) / sizeof(s[0]));
itemsD.mySort();
itemsS.mySort();
I made a constructor/destructor for it, but I don't know how to create two different functions with templates for the two different types of lists.
I think I would need to use some kind of overloading but don't know how.
template <typename T>
class FooCl
{
private:
T *mItems;
int mItemsSize;
public:
FooCl(T items[], int itemsSize)
{
mItems = new T[itemsSize];
for (int i=0; i<itemsSize; ++i)
{
this->mItems[i] = items[i];
}
this->mItemsSize = itemsSize;
};
~FooCl()
{
delete[] mItems;
}
void mySort()
{
//I have no idea how to write this function, so it can sort two different types of lists.
}
};
If you want to sort any container like std::array or std::vector
template <typename Container, typename Func>
void sort(Container& c, Func functor)
{
std::sort(std::begin(c), std::end(c), functor);
}
usage
std::vector<int> vct {1,2,3,1,2};
sort(vct, [](const int lhs, const int rhs) {return lhs > rhs;});
One way is to use std::sort as shown below:
void mySort()
{
//--vvvvvvvvv------------------------------------>use std::sort
std::sort(mItems, mItems + mItemsSize);
}
You can even write your sort functionality/implementation which will include the use of mItems and mItemsSize.
The two operations important for sorting is comparison and swapping.
Both double and std::string already have definitions for <, which is the idiomatic comparison operator.
There is already a template std::swap, which is the idiomatic swap function.
You need to write a sort that uses mItems and mItemsSize, comparing items (with <) and swapping those that are in the wrong position (with std::swap).
I have a list filled with this struct:
struct singlePaymentStruct
{
std::string payer;
int payment;
double amount;
std::time_t timeRec;
singlePaymentStruct() {
payer="Empty";
payment=0;
amount=0;
timeRec = time(0);
}
};
I want to be able to sort this list by any of the fields. How exactly do I do this?
I didn't quite understand how sort method works with something more complex than just a list of records...
Solution found:
singlePaymentList.sort( []( const singlePaymentStruct &a, const singlePaymentStruct &b)
{return a.payer > b.payer;}
);
1.overloading operator<
you can do this by overloading the < operator
struct Foo{
int bar;
bool operator<(Foo &x){
return bar < x.bar;
}
};
2.using lambda expressions
(what is lambda expression?)
Foo array[10];
std::sort(array,array + 10,[](Foo const &l, Foo const &r) {
return l.bar < r.bar; });
3.using custom compare functions
If the possible fields to be used for sorting are known prior, it may be easier to read to implement custom compare functions specifically for the sorting.
struct Foo {
int bar;
SpecialType daa; // Assume daa.IsLessThan() available.
static bool lessBar(const Foo& l, const Foo& r) {
return l.bar < r.bar;
}
static bool lessDaa(const Foo& l, const Foo& r) {
return l.daa.IsLessThan(r.daa);
}
};
Foo array1[10]; // To be sorted by Foo::bar
Foo array2[10]; // To be sorted by Foo::daa
std::sort(array1, array1+10, Foo::lessBar);
std::sort(array2, array2+10, Foo::lessDaa);
std::sort accepts a third optional parameter that is a comparator function. This function should behave as < between elements (i.e. return true when the first is "less than" the second.
For example to sort an std::vector of your structures on increasing payment value what you can do is:
std::sort(data.begin(), data.end(),
[](const singlePaymentStruct& a, const singlePaymentStruct& b) {
return a.payment < b.payment;
});
let the array be struct singlePaymentStruct a[N]
sort(a,a+N,cmp);
bool cmp(struct singlePaymentStruct x, struct singlePaymentStruct y)
{
return x.field < y.field ; //or anything you want to do and return boolean
}
How it works under the hood?
Simply put basically it uses some sorting algoritm like quicksort or mergesort.
Why do we specify comparator functor ?
Well we need that comparator functor to decide the ordering of elements.
The basic thing is in any sorting algortihm the basic operation is comparison..and if we can specify that we are basically controlling the sorting operation.
Hope now you get the pieces together. That's why cmp() takes two values which it will compare and based on which order them.
I would like to compare a vector with an array assuming that elements are in different order.
I have got a struct like below (this struct hasn't got "operator==" and "operator<" -> so I can't use sort):
struct A
{
int index;
A(int p_i) : index(p_i) {}
};
The size of the vector and the array is the same:
std::vector<A> l_v = {A(1), A(2), A(3)};
A l_a[3] = {A(3), A(1), A(2)};
I am looking for some function from std like below "some_function_X" which can find element in specific way using lambda, or function which can compare only specific field like "lhs.index == rhs.index" -> by specific field in class without "operator==" and "operator>" etc.
bool checkIfTheSame(const std::vector<A>& l_v, const A& l_a)
{
for(usigned int i=0; i< 3; ++i)
{
if(!std::some_function_X(l_v.begin(), l_v.end(), l_a,
[](const A& lhs, const A& rhs){
return lhs.index == rhs.index;
})) return false;
}
return true;
}
Thanks.
this struct hasn't got "operator==" and "operator<" -> so I can't use sort
Firstly, only operator< is required. Secondly, it doesn't have to be defined as a member function. The following free function works with std::less (which is what std::sort uses if you don't pass a functor for comparison).
bool operator<(const A& a, const A& b) {...}
Or, you can use a custom comparison functor instead of std::less.
Sorting the array and the vector and then comparing should have better asymptotic runtime complexity than trivially iterating one and checking if the element exists in the other using linear search.
Another idea would be to sort only one of them, iterate the unordered and test the existence in sorted container with binary search. That has same asymptotic complexity as sorting both.
If you can't modify either container, then you can make a copy for sorting. That costs some memory, but is still asymptotically faster than the trivial approach. std::partial_sort_copy can save you a few copies by sorting directly to the copy.
look here : http://www.cplusplus.com/reference/algorithm/
find with lambda expression find if
function which can compare only specific field like "lhs.index == rhs.index" -> by specific field in class without "operator==" and "operator>" etc.
to check if your 2 containers contains same datas with a predicate : equal with a custom predicate
if you just want to check if your container container a specific value, have a look here : How to find if an item is present in a std::vector?
I'm not sure I fully understand what you want but I'll take a guess that you want to check whether two arrays (which have different container types) are equivalent, that is for each item in array A there is a corresponding item somewhere in array B for which some predicate returns true.
You want to do this on two arrays that are not only of different types, but also possibly in a different order.
This is one way to do it:
struct Foo
{
Foo(int i) : _index { i } {}
int index() const {
return _index;
}
private:
int _index;
};
// params:
// first1, last1 bound the first array
// first2, last2 bound the second array
// pred is a predicate that checks for equivalents
// order is a predicate that performs weak ordering
template<class Iter1, class Iter2, class Pred, class Order>
bool checkIfTheSame(Iter1 first1, Iter1 last1, Iter2 first2, Iter2 last2, Pred pred, Order order)
{
const auto len1 = last1 - first1;
const auto len2 = last2 - first2;
if (len1 != len2)
return false;
using namespace std;
using item1_type = typename std::iterator_traits<Iter1>::value_type;
using item2_type = typename std::iterator_traits<Iter2>::value_type;
std::vector<std::reference_wrapper<item1_type>> refs1 { first1, last1 };
std::sort(begin(refs1), end(refs1), order);
std::vector<std::reference_wrapper<item2_type>> refs2 { first2, last2 };
std::sort(begin(refs2), end(refs2), order);
for (size_t i = 0 ; i < len1 ; ++i) {
if (!pred(refs1[i], refs2[i]))
return false;
}
return true;
}
simple example:
using namespace std;
bool same_indexes(const Foo& f1, const Foo& f2) {
return f1.index() == f2.index();
}
bool sort_indexes(const Foo& f1, const Foo& f2) {
return f1.index() < f2.index();
}
int main(int argc, const char * argv[])
{
vector<Foo> x { 1, 2, 3 };
Foo y[] = { 3, 2, 1 };
cout << checkIfTheSame(begin(x), end(x), begin(y), end(y), same_indexes, sort_indexes) << endl;
return 0;
}
If you do not have any way to sort the array or the vector, but you are only able to know if two elements are equal, the only method is an exhaustive search.
Note: While writing this question, I think I already found the answer. Feel free to ammend or append it with a better version. I thought it might be nice to document my problem. edit I was wrong, my aswer was not correct.
Considering a list of integer pairs: I'd like to topologically sort them based on a partial ordering. This is similar to Is partial-order, in contrast to total-order, enough to build a heap? , but I'd like to use std::sort instead of std::priority_queue.
To do so I wrote this piece of code:
#include <iostream>
#include <vector>
#include <algorithm>
struct pair {
int a, b;
pair(int a, int b) : a(a), b(b) {}
std::ostream &print(std::ostream &out) const {
return (out << "(" << a << ", " << b << ")");
}
};
std::ostream &operator<<(std::ostream &out, const pair &p) { return p.print(out); }
struct topological_pair_comparator {
bool operator()(const pair &p, const pair &q) const { return p.a<q.a && p.b<q.b; }
} tpc;
std::vector<pair> pairs = {
pair(1,1),
pair(1,2),
pair(2,1),
pair(3,1),
pair(1,3),
pair(5,5),
pair(2,2),
pair(4,0)
};
int main() {
std::sort(pairs.begin(), pairs.end(), tpc);
for(const pair &p : pairs) std::cout << p << " ";
std::cout << std::endl;
return 0;
}
Source: http://ideone.com/CxOVO0
Resulting in:
(1, 1) (1, 2) (2, 1) (3, 1) (1, 3) (2, 2) (4, 0) (5, 5)
Which is pretty much topologially sorted (proof by example ;).
However, the partial ordering creates that !((1,2) < (2,1)) and !((1,2) > (2,1)) according to the tpc, and hence one may conclude (1,2) == (2,1). However, paragraph 25.4.3 of the c++ standard (January 2012 working draft) states:
For all algorithms that take Compare, there is a version that uses operator< instead. That is, comp(*i,
*j) != false defaults to *i < *j != false. For algorithms other than those described in 25.4.3 to work
correctly, comp has to induce a strict weak ordering on the values.
Edited: According to ecatmur 's valid answer:
A partial ordering is not necessarily a strict weak ordering; it breaks the transitivity of incomparibility. So I'd like to drop my reasoning that a partial ordering is always a strict weak ordering and the associated questions, and add the question: am I doomed to write my own topological sorting algorithm or use the boost implementation which requires me to build the graph?
Solution: A smart suggestion of ecatmur:
struct topological_pair_comparator {
bool operator()(const pair &p, const pair &q) const { return (p.a + p.b) < (q.a + q.b); }
} tpc;
Source: http://ideone.com/uoOXNC
Please note, the SO about heaps does not explicitely mention that std::sort sorts topologically; except for one comment, which is not backed up by argumentation.
Consider the values
pair
x{0, 1},
y{2, 0},
z{1, 2};
Here,
!tpc(x, y) && !tpc(y, x);
!tpc(y, z) && !tpc(z, y);
However,
tpc(x, z);
Thus your comparator does not impose a strict weak ordering, and behavior is undefined if you use it with std::sort or in any other role where a strict weak ordering is required.
A comparator that is strict weak and is a refinement of your comparator would be:
struct refined_comparator {
bool operator()(const pair &p, const pair &q) const { return p.a + p.b < q.a + q.b; }
} rc;
I know how does heap work and how it arranges min and max elements. It is easy, if vector contains only int, to apply make_heap in STL. But how to apply make_heap() if vector contains structure of string and int. Iwant to make heap based on int value in structure.
Please tell me how to do that.
You have to provide comparison function for your structure:
struct A
{
int x, y;
};
struct Comp
{
bool operator()(const A& s1, const A& s2)
{
return s1.x < s2.x && s1.y == s2.y;
}
};
std::vector<A> vec;
std::make_heap(vec.begin(), vec.end(), Comp());
Yes, you can use std::make_heap with std::pair<int, std::string> directly because std::pair has the required less-than comparison operator<. There is even an example in the reference linked above using that particular instantiation of std::pair.