Reputation: 331
I have encountered one coding problem regarding sorting a 2D vector (matrix) using a desired criteria using std::sort
from library algorithm
For example let's say I have a 2D vector
1,8,3
1,9,1
1,4,2
^
and I want to sort it by 3rd column (for example growth criteria) So after sorting I want to have a matrix:
1,9,1
1,4,2
1,8,3
^
I know that in order to specify sorting criteria in std::sort
, third function needs to be sent in std::sort
. If it were a 1D vector
it would not be a problem. I would make a lambda inside std::sort
with 2 parameters, compare them and return true/false.
So now you can see the problem I am facing, how can I access specific elements inside a matrix, in my case third column elements and compare them with std::sort
?
#include <iostream>
#include <vector>
#include <algorithm>
void printMatrix(std::vector<std::vector<int>> m) {
for(int i = 0; i < m.size(); i++) {
for(int j = 0; j < m[i].size(); j++) {
std::cout << m[i][j] << " ";
}
std::cout << std::endl;
}
}
int main() {
std::vector<std::vector<int>> m{
{1,8,3},
{1,9,1},
{1,4,2}
};
std::sort(m.begin(), m.end(), [](int a, int b) { // error
// ???
});
printMatrix(m);
return 0;
}
I would not like to use any other external libraries to solve this problem.
Any help is very appreciated! :)
Upvotes: 4
Views: 1457
Reputation: 1834
Although not the most efficient solution, the simplest thing to do would be to transpose your 2D vector (aka matrix) sort each vector and then transpose again. Here is a tested, working function that will do this for you:
template<typename T>
void sortColumns(vector<vector<T> > &v){
vector<vector<T> > rv(v[0].size(), vector<T>(v.size()));
for(int i = 0; i < v.size(); i++){
for(int j = 0; j < v[i].size(); j++){
rv[j][i] = v[i][j];
}
}
for(int i = 0; i < rv.size(); i++){
sort(rv[i].begin(), rv[i].end());
for(int j = 0; j < rv[i].size(); j++){
v[j][i] = rv[i][j];
}
}
}
Again this isn't the most efficient or the most modern way to sort a matrix by columns but it works and is simple to understand.
Upvotes: 0
Reputation: 21576
std::sort(m.begin(), m.end(), [](int a, int b) { // error
// ???
});
The value_type
of the iterators returned by m.begin()
and m.end()
is a std::vector<int>
. Hence, your lambda needs to take that type for both of its parameters.
std::sort(m.begin(), m.end(),
[](const std::vector<int>& a, const std::vector<int>& b) {
return a.at(2) < b.at(2);
});
Note: I am using the at()
member function here rather than operator []
to prevent UB should you ever mistakenly attempt to sort by in invalid index.
Upvotes: 3
Reputation: 206567
When you want to sort a std::vector<std::vector<int>>
, the items of the container are of type std::vector<int>
, not int
. Hence, you cannot use a lambda
with the declaration
[](int a, int b) { ... }
to sort such a container. You need to use a lambda
with the declaration
[](std::vector<int> a, std::vector<int> b) { ... }
or
[](std::vector<int> const& a, std::vector<int> const& b) { ... }
Using the first version is expensive since it will end up making copies of std::vector
for each call to the lambda
. Hence, it is recommended to use the second version.
std::sort(m.begin(), m.end(), [](std::vector<int> const& a,
std::vector<int> const& b) {
return a.back() < b.back();
});
Upvotes: 2