I've been looking around on the internet trying to find out how to sort a multidimensional array by column and i found a way that works but I'm not sure exactly how it works. Can someone explain it to me?
Arrays.sort(data, (int[] num1, int[] num2) ->
Integer number1 = num1[1];
Integer number2 = num2[1];
return number2.compareTo(number1);
});
in this care the code sorts the array [][] in descending order by the second column.
A two dimensional array is an array whose elements are arrays (int[] in your case). Therefore, in order to sort such an array, you should supply a comparator that compares int[] objects. This is exactly what the lambda expression in your code snippet does. It accepts two int[] objects and determines their relative order by comparing the elements at the second position (i.e. index 1) of the two arrays.
The lambda expression is a feature added in Java 8. It allows you to supply an implementation to a functional interface (which is an interface with a single method, such as Comparator<int[]>, whose single method is int compare (int[] first, int[] second)) without most of the syntax required for anonymous class instances.
Related
This Lambda 8 method came up in one of the suggested answers on leetcode.com: https://leetcode.com/problems/merge-intervals/discuss/21222/A-simple-Java-solution
Below is the method I cannot seem to understand:
int[][] intervals = {{8,10}, {1,3},{2,6},{15,18}};
Arrays.sort(intervals, (i1, i2) -> Integer.compare(i1[0], i2[0]));
I understand that the Arrays.sort() sorts the array in ascending order and the second argument is supposed to be the range it sorts the array.
What I don't understand is the i1 and i2 arguments and the Integer.compare() method that follows.
What exactly are i1 and i2 here? Are they arrays or the integers?
How come we don't write (int i1, int i2)? Is this because we have already mentioned Integer afterward?
I understand that the Arrays.sort() sorts the array in ascending order and the second argument is supposed to be the range it sorts the array.
That is not correct. When you read the javadocs you can see that the second argument is a Comparator - method that defines "rules" on how the array is supposed to be sorted.
int[][] is an array of arrays of ints. If you take a single element of that, it will be plain array of ints - int[]. That is the element you want to be comparing in the sort method and that is what i1 and i2 are. But those are just variable names used inside of the lambda - those could be anything else.
Integer.compare(i1[0], i2[0]) this takes first elements of each array and compares based on that.
How come we don't write (int i1, int i2)? Is this because we have already mentioned Integer afterward?
The method is defined as public static <T> void sort(T[] a, Comparator<? super T> c). When you pass int[][] as the first parameter to it, compilator assumes that second has to be of type Comparator<? super int[]>. Because of that, parameters of the lambda are int[] as well.
The second argument is the comparator you are using to sort your array.
The arrays you are trying to sort is a two-dimension array, so you need to provide a comparator to sort an array of arrays with size two.
With this lambda expression you are comparing two arrays, i1 and i2 with size equal two. Integer.compare(i1[0], i2[0]) is comparing the two arrays of size two based upon their first element.
the sort method is generic method defined like:
public static <T> void sort(T[] a, Comparator<? super T> c)
as you see the type of Comparator c implementation is being inferred during the method's call and, because in your situation, intervals is array of in arrays the expected type of i1 and i2 will be int[]
Arrays.sort takes as a second argument a Comparator<T>.
A Comparator<T> is an interface, and its implementations will take two elements of type <T> and determine which goes first. So, implementing the Comparator interface is useful when you need to sort elements that are not primitive types (like int, char, etc).
In this case the elements that need to be sorted by Arrays.sort are not primitives but other arrays of two elements, so it won't be able to sort them, it needs to know how. So that's why it is providing that Comparator implementation as a second argument.
You see that the lambda is taking i1 and i2 which are arrays, and comparing them by its first element ix[0].
I was practicing a leetcode problem in java, in one of the solution I find out that a user posted a code in which Array is sorted based on using comparator. I did a small Rnd of comparator in reference website, I got to know it is used for setting sorting order (ascending or descending). Then I opened my IDE to practice the same so I wrote the particular code. but while coding I scretched my mind that it was returing -1 0 & 1. So How Will I got to know it will be sent on descending or ascending.
And Most Important thing HOW COMPARATOR IS WORKING ON THE FOLLOWING INPUT.
int ar [][]= {{7,0}, {4,4}, {7,1}, {5,0}, {6,1}, {5,2}};
Arrays.sort(ar,(a,b)-> a[0]>b[0]?1:-1);
System.out.println(Arrays.deepToString(ar));
Guys I am new to programming please explain in depth, the process of sorting in the above example.
Comparator interface is used to order the objects of user-defined classes. A comparator object is capable of comparing two objects of two different classes. Following function compare obj1 with obj2
Syntax:
public int compare(Object obj1, Object obj2):
it retuern value indicate whether other object is equals, more of less to your object.
0 - if they are equal;
1 - if your object is greater;
-1 - if your object is lesser.
For your case
a[0]>b[0]?1:-1
you are just comparing 0 index of every subarray.
Could someone possibly explain why the following:
Integer[] arr1 = {1,2,3,4,5};
Collection<?> numbers = Arrays.asList(new Integer[]{1,2,3});
System.out.println(Arrays.asList(arr1).containsAll(numbers));
print "true", while if we exchange Integer for int like so:
int[] arr2 = {1,2,3,4,5};
Collection<?> numbers2 = Arrays.asList(new int[]{1,2,3});
System.out.println(Arrays.asList(arr2).containsAll(numbers2));
"false" is printed?
In the second case, each list consists of a single element. The two elements are both int[] arrays. The list containing the larger array does not contain the member of the list containing the smaller array.
The Arrays.asList() method accepts a variable argument list of arguments of type T, and returns a List<T>. With an array of Integers, T can be Integer, and the return type List. But with a primitive array, T cannot be an int, because there cannot be a List<int>.
List is a collection of objects and it works great if you put objects in it. As you are trying to create a list using primitive array, JVM is kind enough not to throw an exception but it is not able to create the list as you desired. And hence you see a difference in outputs when you you create a list with Integer array, which is valid and when you create a list with int array which is syntactically correct but logically against the principle of Collections.
according to this: What is the difference between an int and an Integer in Java and C#?
Integer is an Object and int is a primitive tho they are not directly the same...
So in the Java docs the Collection.containsAll(Object o) wants a Object and not a primitive.
Maybe this explains the different
http://docs.oracle.com/javase/6/docs/api/java/util/Collection.html#contains(java.lang.Object)
Didn't know this myself before thanks a lot for your Question.
I have an array of doubles, in Java : arr1 which I want to sort. Most probably the first option would be the utility method Arrays.sort(double[]).
The idea is that I want the same changes (e.g. value at index i is interchanged with value at index j in arr1) to be reflected in another array of integers: arr2 (in the sense that the values at the same indexes are changed also in arr2).
Is there a simple way (a trick) to accomplish this in Java? Or the only way is to implement the sorting algorithm by myself?
UPDATE: I see that people recommend replacing the two arrays with one array of objects containing the 2 values (one from arr1 and one from arr2). Wouldn't this bring some efficiency penalties. In other words, isn't it less efficient to sort an array of objects than an array of primitive types (doubles in this case) ?
The data is completely static. It's large (it fits in memory) but static.
Rather than trying to maintain sorted parallel arrays, a cleaner solution would be to create a class that encapsulates both of your data values, and just have one array of objects.
(But to answer your question, there is no built-in way to do this in Java. Implementing your own sort routine that keeps two arrays sorted based on values in one of them would work for a small amount of data that isn't likely to change, but it would be difficult to maintain.)
One solution which is doesn't impact the performance of sorting, ie still O(nlog(n)) time complexity.
Use a map to store array[i] -> i
Sort the array
Iterate over the sorted array, and for each value, use it as a key for the map to retrieve the original index.
Edit: Raihan comment make me look miserable :(
Try it this way....
- Convert this array into ArrayList using the Arrays.asList()
- Create another List Object Reference Variable and assign the same ArrayList object to it, Now any changes to the first ArrayList will be reflected to the Second ArrayList.
Eg:
double[] array = new double[10];
ArrayList<Double> arList_1 = new ArrayList<Double>(Arrays.asList(array));
ArrayList<Double> arList_2 = arList2;
Now for sorting, there are 2 options:
- Use java.lang.Comparable Interface, if you want to sort it in only 1 way.
- Use java.util.Comparator Interface, if you want to sort it in more than 1 way.
Note sure what are you looking for but one other work around could be like this.
Create a map to maintain the relation between arr1 and arr2 elments
Map<Double, Double> myLocalMap<Double, Double>();
for(int ind=0; indx < arr1.length; indx++){
myLocalMap.put(Double.valueOf(arr1[indx]), Double.valueOf(arr2[indx]));
}
Now sort arr1 as you said:
Arrays.sort(arr1);
Once arr1 is sorted, update arr2 as below:
for(int ind=0; indx < arr1.length; indx++){
arr2[indx] = myLocalMap.get(arr1[indx]).doubleValue();
}
I had to write a merge sort function in Java. No problem. Well, a little, but I got through it. Then the follow up question I didn't get.
Question: Given an array A[][] such that A[i][0] is a float and A[i][1] is a nonnegative int giving the multiplicity of the value A[i][0] (here think of a big vector that's been collapsed down by combining repeated entries and recording how many got combined), write a version of merge sort that returns B[][] where B[i][0] < B[i+1][0] for all i.
Any ideas? The best I could do was merge sort and then group the equal ones, but apparently you can do it all in one step.
Strage question... and using different types in these arrays is just ugly (personal point of view).
However, the most useful thing to do, is to rewrite your merge function with a Comparator.
This way you can sort using whatever property you want.
You would end up with a signature like void merge(A[] arr, Comparator<? super A> comp).
By the way, the Java implementation of sort is a lot like this.
To solve your question you would call:
A[][] a = ...;
merge(a, new Comparator<A[]>() {
int compare(A[] a, A[] b) {
return ((Float)a[0]) - ((Float)b[0]);
}
});