Reputation: 15574
I have a 2D array like below. ( array[5][2]
)
20 11
10 20
39 14
29 15
22 23
after sorting it should be like below.
10 20
20 11
22 23
29 15
39 14
that means the array should be sorted comparing the first column values only.
In Java there is a built in function capability to do that. like below.
Arrays.sort(a, new Comparator<Long[]>() {
@Override
public int compare(Long[] o1, Long[] o2) {
Long t1 = o1[1];
Long p1 = o1[0];
Long t2 = o2[1];
Long p2 = o2[0];
if (t1 == t2) {
return (p1 > p2 ? 1 : (p1 == p2 ? 0 : -1));
} else {
return (t1 < t2 ? -1 : 1);
}
}
});
So is there any C++ built in function capability to do these kind of stuff or how can i do this in C++ (the fastest implementation) ?
Thanks in advance :)
Upvotes: 18
Views: 78052
Reputation: 411
We can simply use sort on row or column basis using inbuilt sort function in c++. We have to just pass compare function with proper arguments.
Here is an example of sorting 2D array column wise.
#include<iostream>
#include<algorithm>
using namespace std;
bool compare(int *a, int *b){
// sorting on basis of 2nd column
return a[1] < b[1];
}
void sorting(int **arr,int n){
//calling in built sort
sort(arr, arr + n, compare);
// printing after sorting
cout<<"---------After Sorting---------"<<endl;
for(int i = 0; i < n; i++){
cout<<arr[i][0]<<" "<<arr[i][1]<<endl;
}
}
int main(){
int **arr, i, n;
cout<<"Enter the size of array : ";
cin>>n;
//array of size arr[n][2];
arr = new int*[n];
for(i = 0; i < n; i++){
arr[i] = new int[2];
}
for(int i = 0; i < n; i++){
cin>>arr[i][0];
cin>>arr[i][1];
}
sorting(arr, n);
return 0;
}
Upvotes: 3
Reputation: 438
To be honest, since you have only two ints
in your second dimension, I would use instead an array of pairs, which have their own built in comparison function. With something like pair<int,int> arr[200]
, you would be able to call the built in sort function sort(arr, arr + 200)
, which would sort your array by first element, and then by the second element.
#include <iostream>
#include <algorithm>
using namespace std;
int main()
{
// pair of integers
pair<int, int> arr[1000];
// fill array with random numbers
random_device rd;
mt19937 rng(rd());
uniform_int_distribution<int> uni(0,1000);
for(int i = 0; i < 10; i++) {
// make_pair(x, y) creates a pair with two integers x and y
arr[i] = make_pair(uni(rng), uni(rng));
}
// prints out initial array
cout << "BEFORE ARRAY..." << endl;
for(int i = 0; i < 10; i++) {
// .first and .second call the first and second ints in the pair respectively
cout << arr[i].first << " " << arr[i].second << endl;
}
cout << endl;
// sort the array by calling built in sort function
sort(arr, arr + 10);
// prints out array
cout << "FINAL ARRAY..." << endl;
for(int i = 0; i < 10; i++) {
cout << arr[i].first << " " << arr[i].second << endl;
}
cout<<endl;
}
When you run this program, you see that the arrays are now sorted:
BEFORE ARRAY...
726 562
916 348
594 6
515 872
976 960
662 169
529 317
789 702
74 255
330 574
FINAL ARRAY...
74 255
330 574
515 872
529 317
594 6
662 169
726 562
789 702
916 348
976 960
Note how the second elements are also sorted, but secondary to the
Upvotes: 6
Reputation: 38919
First off, if you'd given vector<vector<int>> array
this would be sortable just using: sort(begin(array), end(array))
because vector
defines lexicographic comparison functions: http://en.cppreference.com/w/cpp/container/vector/operator_cmp
That said, there are drawbacks to using a vector
-of-vector
s: What are the Issues with a vector-of-vectors? and it's clearly not what you intended. Given int array[5][2]
trying to use sort
will yield:
error C3863: array type 'int [2]' is not assignable
Instead of using swap
to exchange 2 int[2]
s we need to simply need to swap bytes of sizeof(*array)
, that can be accomplished using qsort
as suggested by WhozCraig's answer, but we can improve upon that making our comparator capable of handling any size sub-array. Given int array[5][2]
or whatever dimensions are desired we can write:
static const auto SIZE = size(*array);
qsort(array, size(array), sizeof(*array), [](const auto lhs, const auto rhs) {
const auto first = reinterpret_cast<const int*>(lhs);
const auto last = next(first, SIZE);
const auto its = mismatch(first, last, reinterpret_cast<const int*>(rhs));
if (its.first == last) {
return 0;
} else if (*its.first < *its.second) {
return -1;
} else {
return 1;
}});
A quick note array
should not be used as a variable name as it defines a standard type, with this change you can find an example here: http://ideone.com/87AoIr
Upvotes: 6
Reputation: 4847
The built-in arrays of C and C++ are very inflexible, among other things they cannot be assigned.
Your best option would be the 'array' class from the C++ standard library, at least for the inner dimension:
array<int, 2> a[5] = { { 20, 11 },
{ 10, 20 },
{ 39, 14 },
{ 29, 15 },
{ 22, 23 } };
sort( a, a + 5 );
Here we use the property of std::array that '<' by default compares them lexicographically, i.e. starts with the first element. In order to sort things differently we have to come up with an comparator object, so if you want to use the second column as sort key you have to do this:
auto comp = []( const array<int, 2>& u, const array<int, 2>& v )
{ return u[1] < v[1]; };
sort( a, a + 5, comp );
And as mentioned in the first comment, sort(a, a+5 ...
is just an ugly short form for the cleaner sort(std::begin(a), std::end(a) ...
Upvotes: 12
Reputation: 3812
If you can, use Vector
with some struct to hold two int
:
typedef std::pair<int, int> pairType;
std::vector<pairType> vec;
// Initialize vector
std::sort(std::begin(vec), std::end(vec), [](pairType& first, pairType& second)->bool { return first.first < second.first });
Upvotes: 3
Reputation: 66194
I'm offering this up only because it was one of the few things std::qsort
does well that std::sort
simply does not, namely sort multi-column fixed arrays: The comparator is a string of ternary statements, but should be clear enough if you stare at it long enough:
#include <iostream>
#include <random>
#include <algorithm>
int main()
{
int ar[10][2];
// populate with random data
std::random_device rd;
std::default_random_engine rng(rd());
std::uniform_int_distribution<> dist(1,20);
std::for_each(std::begin(ar), std::end(ar),
[&](int (&ar)[2]){ ar[0] = dist(rng); ar[1] = dist(rng); });
std::cout << "Before Sort..." << '\n';
std::for_each(std::begin(ar), std::end(ar),
[](const int(&ar)[2]) { std::cout << ar[0] << ',' << ar[1] << '\n';});
std::qsort(ar, 10, sizeof(*ar),
[](const void *arg1, const void *arg2)->int
{
int const *lhs = static_cast<int const*>(arg1);
int const *rhs = static_cast<int const*>(arg2);
return (lhs[0] < rhs[0]) ? -1
: ((rhs[0] < lhs[0]) ? 1
: (lhs[1] < rhs[1] ? -1
: ((rhs[1] < lhs[1] ? 1 : 0))));
});
std::cout << "After Sort..." << '\n';
std::for_each(std::begin(ar), std::end(ar),
[](const int(&ar)[2]) { std::cout << ar[0] << ',' << ar[1] << '\n';});
return 0;
}
Sample Run (yours will vary, obviously)
Before Sort...
2,11
18,4
20,20
14,6
8,10
17,8
14,14
3,10
20,14
19,19
After Sort...
2,11
3,10
8,10
14,6
14,14
17,8
18,4
19,19
20,14
20,20
Notes: this specifically uses strict-value comparison rather than subtraction short-cuts in the comparator so as to avoid potential underflow issues. If that is not a problem in your restricted data-space, you could easily make that comparator significantly simpler.
Upvotes: 16
Reputation: 21576
The fastest way to sort a 2D array in time(using only columns) . . .will cost you reference locality... Else, every other way will involve lots of copying of rows.. . . Though (C++'s move operations may cushion this)
You would create a new array of pointers to a 2D array... Then sort the pointers...
Else, every other answer before mine seems good. But I advise you to use std::array.
Upvotes: 1
Reputation: 47784
If end container doesn't matter, how about using a map ?
#include<map>
std::map<int, int> m;
for(std::size_t i = 0; i < 5; ++i )
m[array[i][0]] = array[i][1] ;
You can now copy m
back to your array
std::size_t i=0;
for(const auto& x:m)
{
array[i][0] = x.first ;
array[i++][1] = x.second ;
}
Upvotes: 0