This question already has answers here:
Sorting a std::vector<std::pair<std::string,bool>> by the string?
(5 answers)
Closed 9 years ago.
I have a question about sorting a vector of pairs:
std::vector<std::pair<double,Processor*>> baryProc;
this vector is already filled up with the pairs.
Now I wanted to sort the pairs inside the vector based on the double value inside the pair
EXAMPLE:
suppose I have 3 pairs inside the vector. pair1 is at front and pair 3 is at end. pair2 is in the middle:
pair1(1, proc1)
pair2(3, proc2)
pair3(2.5, proc3)
now i want to sort the pairs based on the double value. So that the order inside the vector is:
pair1(1, proc1)
pair3(2.5, proc3)
pair2(3, proc2)
How could I do this? I am quite stuck.
#include <algorithm>
int main(){
std::vector<std::pair<double,Processor*>> baryProc;
std::sort(baryProc.begin(),baryProc.end());
}
Note that you do not need a custom comparator because the default comparator of pair does the thing you want. It first compares by the first element and if they are identical, it compares the second element in the pair.
In C++, you can have custom comparator functions that specify how to decide whether one element goes before another when sorting. In your case, given 2 pairs, you want the one with the lower value for the first element to go before the other one. You can write a comparator function like so:
// This function returns true if the first pair is "less"
// than the second one according to some metric
// In this case, we say the first pair is "less" if the first element of the first pair
// is less than the first element of the second pair
bool pairCompare(const std::pair<double, Processor*>& firstElem, const std::pair<double, Processor*>& secondElem) {
return firstElem.first < secondElem.first;
}
Now, pass this function into your sort method:
//The sort function will use your custom comparator function
std::sort(baryProc.begin(), baryProc.end(), pairCompare);
Related
I am relative new at C++ and I have little problem. I have vector and in that vector are vectors with 3 integers.
Inner vector represents like one person. 3 integers inside that inner vector represents distance from start, velocity and original index (because in input integers aren't sorted and in output I need to print original index not index in this sorted vector).
Now I have given some points representing distance from start and I need to find which person will be first at that point so I have been thinking that my first step would be that I would find closest person to the given point so basically I need to find lower_bound/upper_bound.
How can I use lower_bound if I want to find the lower_bound of first item in inner vectors? Or should I use struct/class instead of inner vectors?
You would use the version of std::lower_bound which takes a custom comparator (the versions marked "(2)" at the link); and you would write a comparator of vectors which compares vectors by their first item (or whatever other way you like).
Howerver:
As #doctorlove points out, std::lower_bound doesn't compare the vectors to each other, it compares them to a given value (be it a vector or a scalar). So it's possible you actually want to do something else.
It's usually not a good idea to keep fixed-length sequences of elements in std::vector's. Have you considered std::array?
It's very likely that your "vectors with 3 integers" actually stand for something else, e.g. points in a 3-dimensional geometric space; in which case, yes, they should be in some sort of class.
I am not sure that your inner things should be std::vector-s of 3 elements.
I believe that they should std::array-s of 3 elements (because you know that the size is 3 and won't change).
So you probably want to have
typedef std::array<double,3> element_ty;
then use std::vector<element_ty> and for the rest (your lower_bound point) do like in einpoklum's answer.
BTW, you probably want to use std::min_element with an explicit compare.
Maybe you want something like:
std::vector<element_ty> vec;
auto minit =
std::min_element(vec.begin(), vec.end(),
[](const element_ty& x, const element_ty&y) {
return x[0] < y[0]));
I need suggestion to use STL containers in the best possible way to sort 3 sets of data
1. A ID (Integer)
2. First Value (String)
3. Second Value (String)
An example of the data structure is as below:
I want to use map as it is sorted at the time of insert and no need to execute a sorting algorithm separately. Since the ID can repeat it must be a multimap, and each data of a column is linked to each other so the rows will change in order to sort keeping the same values attached to a ID.
Sorting the ID and value is ok, but how do I sort 2 values as multimap can take only one value. From my thinking it will be multimap of a multimap or a struct of the data structure and then STL containers. But I want to make it as simple as possible. I need suggestion on how this can be achieved.
Thanks!
Having a map or a set makes sense if and only if you are going to do many insert/erase operations it. If the data structure is static, storing a vector and sorting it once is way more effective. That said, if I understand your question correctly, I think you don't need a map, but a multiset.
typedef pair<int, pair<string, string>> myDataType;
set<myDataType> mySet;
here, the operator < of pair will take care of the ordering.
If you don't want to refer to the id as elem.first, and to the strings as elem.second.first, and elem.second.second, then you can use a struct and overload operator < for it.
struct myType
{
int id;
string s1;
string s2;
};
bool operator < (const myType& t1, const myType& t2)
{
return make_tuple(t1.id, t1.s1, t1.s2) < make_tuple(t2.id, t2.s1, t2.s2);
}
You could just use a std::set<std::tuple<int, std::string, std::string>>. Tuples are lexicographically compared thus you would get the effect you want for free.
Live Demo
Elements in a multimap are sorted by the Key. You cannot 'sort' multimap. What you can do is to create vector of pairs<Key, Map<Key>::Interator> with elements fulfilling some logical condition and sort vector.
This question already has answers here:
How do I perform a pairwise binary operation between the elements of two containers?
(3 answers)
Closed 8 years ago.
Is there any implemented method in the C++ library which allows you to sum the values of two vectors (of the same size and type of course)?
For example:
std::vector<int> a;//looks like this: 2,0,1,5,0
std::vector<int> b;//looks like this: 0,0,1,3,5
Now then adding their values together should look like this:
//2,0,2,8,5
The answer I'm expecting is either "No there isn't" or "yes" + method.
You can use std::transform and std::plus<int>()
std::vector<int> a;//looks like this: 2,0,1,5,0
std::vector<int> b;//looks like this: 0,0,1,3,5
// std::plus adds together its two arguments:
std::transform (a.begin(), a.end(), b.begin(), a.begin(), std::plus<int>());
// a = 2,0,2,8,5
This form of std::transform takes 5 arguments:
Two first are input iterators to the initial and final positions of the first sequence.
The third is an input iterator to the initial position of the second range.
The fourth is an output iterator of the initial position of the range where the operation results are stored.
The last argument is a binary function that accepts two elements as argument (one of each of the two sequences), and returns some result value convertible to the type pointed by OutputIterator.
I have a matrix consisting of a vector of which each element representing the rows is composed of a vector representing the columns of the matrix. I would like to sort the rows according to the 1st column.
Each element inside this matrix is a double, although the first column contains a number that serves as an identifier (but is not unique).
My goal is to have something like the aggregate functions available in SQL, such as count() and sum() when I group by the first column.
For instance, if I have:
ID VALUE
1 10
2 20
1 30
2 40
3 60
I would like to get:
ID COUNT MEAN
1 2 20
2 2 30
3 1 60
However, I am stuck in the very first step: how do I sort the rows according to the value of the first element of each row?
I found a clue on this topic, and changed adapted the comparator to:
bool compareFunction (double i,double j)
{
return (i<j);
}
But the compiler was not very happy about that (making a reference to the stl_algo.h file):
error: cannot convert 'std::vector<double>' to 'double' in argument passing
I was therefore wondering if there is a way to sort such a vector of vectors when it contains doubles.
Answer (imho): use a different datastructure. What you are trying to do is setup a multimap. Oh hey look:
http://www.cplusplus.com/reference/map/multimap/
stl::multimap - how do i get groups of data?
It'll be faster for large numbers of elements. And is actually a map rather than a vector of vector of double.
Either that, or skip the sorting all together, and count by key using std::map, std::unordered_map, or (if you know the number of keys and/or the keys are offset by 1 with no breaks) std::vector.
To expand, sorting your list to get means will be slow. Sorting (using std::sort) is O(nlogn), and will be O(nlogn) every time you compute this mean. And it is an unessisary step: your stuff is grouped by key reguardless of order. std::map and std::multimap will "sort as you go" which will be just a little faster than sorting every time, but you won't have to sort the whole thing to get the list. Then you can just iterate the multimap to get the mean, O(n) each mean calculation. (It is still O(nlg(n)) to add all the elements to the multimap)
But if you know the key output is going to be 1,2,3...n-1,n, than sorting is a complete waste of time. Just make a counter for each key (since you know what the keys can be) and add to the key while iterating the array.
BUT WAIT THERE IS MORE
If the keys are actually setup the way you are thinking, than the best way from the get go is to forget the table structure, and make build it like this:
Index VALUE
0 10,30
1 20,40
2 60
Count is now constant time for each row. Mean for each row is O(n). Getting a list is constant time for each row. EVERYBODY WINS.
You need to create a comparator function comparing vector<double>:
struct VecComp {
bool operator()(const vector<double>& _a, const vector<double>& _b) {
//compare first elements
}
}
Then you can use std::sort on your structure with the new comparator function:
std::sort(myMat.begin(), myMat.end(), VecComp());
If you are using c++11 features you can also utilize lambda functions here:
std::sort(myMat.begin(), myMat.end(), [](const vector<double>& a, const vector<double>& b) {
//compare the first elements
}
);
You need to write your own comparator functor to pass into your vector declaration:
struct comp {
bool operator() (const std::vector<double>& i,
const std::vector<double>& j) {
return i[0] < j[0];
}
Have you tried just this?:
std::sort(vecOfVecs.begin(), vecOfVecs.end());
That should work as std::vector has operator< which provides lexicographical sorting, which is (a little more specific than) what you want.
This question already has answers here:
how do you insert the value in a sorted vector?
(7 answers)
Closed 11 months ago.
So I have a vector, and I want the elements to be sorted at all times. How should I go about inserting an element into that vector and keeping the elements sorted when I pop them out. I looked into std::lower_bound, however, that gave the opposite of what I wanted.
For example, this is what I want: When I pop all the elements in the vector it should be:
1 2 3 4 5. That means the vector has to store them as 5 4 3 2 1. If use lower bound, the vector stores them as 1 2 3 4 5, and it is popped as 5 4 3 2 1. Also, a compare functor is going to be passed in so that the lower_bound function uses the compare functor. Is there a way to take the opposite of a compare functor?
To keep your vector sorted all the time, you should always insert new elements into proper position. As you want to pop elements in ascending order and vector provides only pop_back() method you should sort elements in descending order. so first you need to find proper position and then insert there:
typedef std::vector<int> ints;
void insert( ints &cont, int value ) {
ints::iterator it = std::lower_bound( cont.begin(), cont.end(), value, std::greater<int>() ); // find proper position in descending order
cont.insert( it, value ); // insert before iterator it
}