Having trouble understanding the following Lambda method from Java 8 - java

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].

Related

Does Array.sort() implements comparable ? When I looked at the Array Class it doesn't ,so How does the sort work here?

How sorting is done here as I can see Arrays class doesn't implement Comparable.
//Add values to Array
int arrayname[]=new int[3];
arrayname[0]=40;
arrayname[1]=10;
arrayname[2]=35;
//Sort the elements
Arrays.sort(arrayname);
//Display values
System.out.println("Values in Array After Sorting:");
for(int i=0;i<arrayname.length;i++){
System.out.print(arrayname[i]+", ");
}
It does not have to.
It uses the type's compareTo method. That means in the case of objects you need to implement the Comparable<T> interface.
See https://docs.oracle.com/javase/7/docs/api/java/util/Arrays.html#sort(java.lang.Object[])
For primitive types, they have a natural ordering already.
You can also pass a lambda or a method reference to have a custom sorting.
If you look into the Arrays.sort() code, it uses a class named ComparableTimSort internally. This class has a method ComparableTimSort.binarySort(Object[] a, int lo, int hi, int start), which actually expects that the elements in parameter a be Comparable.
Since Arrays.sort() is a static method, a utility method, Arrays doesn't directly implement Comparable. It is the elements in the array passed to it that need to be Comparable.

why Arrays.sort() can't sort primitive type array in descending order?

As we know, the following code can work:
Integer[] arr = new Integer[len];
Arrays.sort(arr, (a,b) -> (b - a));
But why we can't do this with an int[], why java doesn't allow this?
Look at the signature of the Arrays#sort method you are trying to use
public static <T> void sort(T[] a, Comparator<? super T> c) {
...
}
Where <T> the class of the objects to be sorted in the Array. Primitive int can't be a convert class.
This is because, the order induced sort method sort(T[] a, Comparator<? super T> c) method uses comparator. As you can not parameterise a Comparator<> with a primitive type, this method has to be used with Objects. Like in Map we can not declare Map<int, boolean>.
I think the answer is the same as this one - the language designers have probably concluded that it would be too much, since creating the methods for all primitives would've dragged with it the need for creating corresponding comparator classes, which would've probably been useless anywhere except in this case.
So one can just sort the array in ascending order and then use the Apache Commons Lang to reverse its elements:
int[] arr = ...
Arrays.sort(arr);
ArrayUtils.reverse(arr);

What is the difference between Java Collections' two toArray() functions?

Located here. Reading through these docs, it's not clear to me the reason that this distinction is made. The difference clearly is that the first method returns an Object array, and it looks like the second returns a Generic array. Could you please explain how these would be implemented differently and what the distinction is between them?
The method
<T> T[] toArray(T[] a)
already gets an array as a parameter and thus is able to return an array with the same base type.
The method
Object[] toArray()
does not know the base type (remind: generic types are erased at runtime), so it can only return an object array.
Simply said: For a Collection<String> you will get a String[] when calling the first method, and you will get an Object[] when calling the second method. And these are different types.
Just a note: This is other as with collections. As generic types are erased at runtime, a List<String> and a List<Object> are the same List type at runtime.
These methods returns the elements of a collection inside an array.
There are two differences between the 2 methods
The first one is not generic (meaning you'll need casting) while the second one is generic
The first one will instantiate a new array, while in the second one you may provide yourself the array that will be used. Its size needs to be equals or greater than the number of elements in the collection (or the method will also have to instantiate an array), but you can provide a bigger one if you plan to add more element to it.
And for your code, it won't compile
List<String> myCollection = new ArrayList<>();
nyCollection.add("example");
Object[] array1 = myCollection.toArray();
// a new array will be created by the toArray method
String[] array2 = myCollection.toArray(new String[0]);
// the provided array will be used
String[] array3 = myCollection.toArray(new String[2]);

How does array.sort work with multidimensional arrays?

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.

Difference in containsAll behavior for Integer and int arrays (Java)

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.

Categories

Resources