Weighted order of List with Null - java

I've been trying to implement a Comparator class which should order a list based on weight of position. I will explain what I should accomplish.
Suppose I have an ArrayList<T>. This array list has always a fixed size, filling other slot with null values.
//fixed size = 3
T myObj1, myObj2;
[myObj1, null, myObj2];
In this example, myObj2 < myObj1, since it is stored in a slot whose position value is less than the first.
An ordering comparator should give this output:
//fixed size = 3
T myObj1, myObj2;
[myObj1, myObj2, null];
Other examples:
//fixed size = 7;
T myObj1, myObj2, myObj3, myObj4;
INPUT = [myObj1, null, null, myObj4, myObj3, myObj2, null];
RESULT = [myObj1, myObj4, myObj3, myObj2, null, null, null];
I thought about using aComparator<T>(The T is a specific class, it does not need to be general actually); is there a way to replicate such behaviour?

You could always make nulls return > 0 in a comparator
if (one == null && two == null) {
return 0;
} else if (two == null) {
return -1;
} if (one == null) {
return 1;
} else {
//Compare logic...
}
This says nulls are "bigger" than non-null values

Instead of writing your own comparator logic, it is usually simpler to use one of the helper methods such as Comparator.comparing.
> List<Integer> foo = Arrays.asList(1, null, 2, null, 1, null);
> Collections.sort(foo, Comparator.comparing(x -> x == null ? 1 : 0));
> foo
[1, 2, 1, null, null, null]
This way the sort is done as if non-null elements are all 0, and nulls are 1, so the nulls will appear after the non-nulls when they are sorted. The non-null elements will remain in their original order, because Collections.sort is stable.
For this specific case as #Zabuza notes, the helper method Comparator.nullsLast does exactly the right thing; the argument is null because there is no "fallback" comparator we want to use for non-null elements.
> Collections.sort(foo, Comparator.nullsLast(null));
That said, this solution takes O(n log n) time for a list of length n, when a two-pointer solution could solve the same problem in O(n) time.

For anyone in need, I figured it out thanks to #tomgeraghty3
public class TComparator implements Comparator<T> {
public int compare(T r1, T r2) {
if (r1 == null && r2 == null) {
return 0;
} else if (r2 == null) {
return -1;
} if (r1 == null) {
return 1;
} else {
return 1;
}
}
}

Related

TimSort violation

What's wrong with this comparator method?
I have read :
Java error: Comparison method violates its general contract
And understand that if c1 > c2, and c2 > c3, then c1 > c3. I believe this should hold true in the above.
getMaxCosine() returns value between 0..1, and 2nd sort is by the length of the text in the card, the longer the higher ranked.
public int compare(Card c1, Card c2) {
if (getMaxCosine(c1) > getMaxCosine(c2)) {
return -1;
} else if (getMaxCosine(c1) == getMaxCosine(c2)) {
return getMatchingText(c1).length() >= getMatchingText(c2).length() ? -1 : 1;
} else {
return 1;
}
}
I think your issue is in your if-else block:
else if (getMaxCosine(c1) == getMaxCosine(c2)) {
return getMatchingText(c1).length() >= getMatchingText(c2).length() ? -1 : 1;
}
If getMatchingText(c1).length() is equal to getMatchingText(c2).length() then you return -1. This yields an "unstable" sort: In other words, the order two objects with equal values will be reversed after sorting. Moreover, you should return 0 for Cards that are equal under this comparator. I suggest changing the >= comparison to just > in this if-else block:
else if (getMaxCosine(c1) == getMaxCosine(c2)) {
if (getMatchingText(c1).length() == getMatchingText(c2).length()) return 0;
return getMatchingText(c1).length() > getMatchingText(c2).length() ? -1 : 1;
}

java.lang.IllegalArgumentException: Comparison method violates its general contract! How to handle possible null objects?

private Comparator<Entity> spriteSorter = new Comparator<Entity>() {
public int compare(Entity e0, Entity e1) {
if (e0 == null || e1 == null) return -1; //was 0
if (e1.getY() < e0.getY()) return +1;
if (e1.getY() > e0.getY()) return -1;
return -1; //was 0
}
};
I have read many articles about this one, but I still don't know how to solve this little problem:
This is the core that works:
if (e1.getY() < e0.getY()) return +1;
if (e1.getY() > e0.getY()) return -1;
But sometimes (I have to deal with many houndred entities which are being added and removed from a concurrent array list very often in a second) one of the entities is null. Therefore I have to check this inside this comparator.
But then I violate this general contract, once one of the two objects is null.
Any idea how I can solve this? Please help! :)
Your comparator, if called with c.compare(null, null), will compare null < null, even though they are equal. Further, it breaks the rule for inverses, which is that sgn(compare(a, b)) == -sgn(compare(b, a)), that is, comparing two things backwards returns the opposite of comparing them forwards. You can fix all this simply by treating null as "negative infinity," that is enforcing that null < a for all nonnull a and null == null.
public int compare(Entity l, Entity r) {
if (Objects.equals(l, r)) return 0; // Handles normal and null equality
else if(l == null) return -1; // Enforce null < a ∀ nonnull a
else if(r == null) return +1; // Enforce a > null ∀ nonnull a
else return Integer.compare(l.getY(), r.getY()); // Base comparison
}

Finding the largest element in an array using recursion in Java

This is what I have so far, but I'm confused on how to keep track of the index. I would change the parameters of the method, but I'm not allowed.
I can only use a loop to make another array. Those are the restrictions.
public class RecursiveFinder {
static int checkedIndex = 0;
static int largest = 0;
public static int largestElement(int[] start){
int length = start.length;
if(start[length-1] > largest){
largest = start[length-1];
int[] newArray = Arrays.copyOf(start, length-1);
largestElement(newArray);
}
else{
return largest;
}
}
/**
* #param args
*/
public static void main(String[] args) {
int[] array1 = {0,3,3643,25,252,25232,3534,25,25235,2523,2426548,765836,7475,35,547,636,367,364,355,2,5,5,5,535};
System.out.println(largestElement(array1));
int[] array2 = {1,2,3,4,5,6,7,8,9};
System.out.println(largestElement(array2));
}
}
Recursive method doesn't need to keep the largest value inside.
2 parameters method
Start to call with:
largestElement(array, array.length-1)
Here is the method:
public static int largestElement(int[] start, int index) {
if (index>0) {
return Math.max(start[index], largestElement(start, index-1))
} else {
return start[0];
}
}
The 3rd line of method is the hardest one to understand. It returns one of two elements, larges of the one of current index and of remaining elements to be checked recursively.
The condition if (index>0) is similar to while-loop. The function is called as long as the index remains positive (reaches elements in the array).
1 parameter method
This one is a bit tricky, because you have to pass the smaller array than in the previous iteration.
public static int largestElement(int[] start) {
if (start.length == 1) {
return start[0];
}
int max = largestElement(Arrays.copyOfRange(start, 1, start.length));
return start[0] > max ? start[0] : max;
}
I hope you do this for the study purposes, actually noone has a need do this in Java.
Try that for the upper class, leave the main method it's is correct.
public class dammm {
public static int largestElement(int[] start){
int largest = start[0];
for(int i = 0; i<start.length; i++) {
if(start[i] > largest){
largest = start[i];
}
}return largest;
}
If your goal is to achieve this by using recursion, this is the code that you need. It is not the most efficient and it is not the best way to deal with the problem but it is probably what you need.
public static int largestElement(int[] start){
int length = start.length;
if (start.lenght == 1){
return start[0];
} else {
int x = largestElement(Arrays.copyOf(start, length-1))
if (x > start[length-1]){
return x;
} else {
return start[length-1];
}
}
}
Imagine that you have a set of numbers you just have to compare one number with the rest of them.
For example, given the set {1,8,5} we just have to check if 5 is larger than the largest of {1,8}. In the same way you have to check if 8 is larger than the largest of {1}. In the next iteration, when the set one have one value, you know that that value is the bigger of the set.
So, you go back to the previous level and check if the returned value (1) is larger than 8. The result (8) is returned to the previous level and is checked against 5. The conclusion is that 8 is the larger value
One parameter, no copying. Tricky thing is, we need to pass a smaller array to the same method. So a global variable is required.
// Number of elements checked so far.
private static int current = -1;
// returns the largest element.
// current should be -1 when user calls this method.
public static int largestElement(int[] array) {
if (array.length > 0) {
boolean resetCurrent = false;
if (current == -1) {
// Initialization
current = 0;
resetCurrent = true;
} else if (current >= array.length - 1) {
// Base case
return array[array.length - 1];
}
try {
int i = current++;
return Math.max(array[i], largestElement(array));
} finally {
if (resetCurrent) {
current = -1;
}
}
}
throw new IllegalArgumentException("Input array is empty.");
}
If you can create another method, everything would be much simpler.
private static int recursiveFindLargest(int [] array, int i) {
if (i > 0) {
return Math.max(array[i], recursiveFindLargest(array, i-1));
} else {
return array[0];
}
}
public static int largestElement(int [] array) {
// For empty array, we cannot return a value to indicate this situation,
//all integer values are possible for non-empty arrays.
if (array.length == 0) throw new IllegalArgumentException();
return recursiveFindLargest(array, array.length - 1);
}
For this problem you really need to think about working with the base case. Take a look at some of the simple cases you would have to deal with:
If the array is length 1, then you return the only value
If the array is length 2, then you return the maximum of the two values
If the array is length 3, then ?
From the above we can get an idea of the structure of the problem:
if array.length == 1 then
return array[0]
else
return the maximum of the values
In the above if we have only one element, it is the maximum value in the list. If we have two values, then we have to find the maximum of those values. From this, we can then use the idea that if we have three values, we can find the maximum of two of them, then compare the maximum with the third value. Expanding this into pseudo code, we can get something like:
if array.length == 1 then
return array[0]
else
new array = array without the first element (e.g. {1, 2, 3} => {2, 3})
return maximum(array[0], largestElement(new array))
To explain the above a little better, think of execution like a chain (example for {1, 2, 3}).
Array: {1, 2, 3}, maximum(array[0] = 1, largestElement(new array = {2, 3}))
Array: {2, 3}, maximum(array[0] = 2, largestElement(new array = {3}))
Array: {3}, array[0] = 3 => length is 1 so return 3
The above then rolls back up the 'tree' structure where we get:
maximum (1, maximum(2, (return 3)))
Once you have the maximum value, you can use the sample principle as above to find the index with a separate method:
indexOf(array, maximum)
if array[0] == maximum then
return 0
else if array.length == 1 then
return -1
else
new array = array without the first element (e.g. {1, 2, 3} => {2, 3})
result = indexOf(new array, maximum)
return (result == -1) ? result : result + 1
For looking into this more, I would read this from the Racket language. In essence it shows the idea of array made purely from pairs and how you can use recursion to do iteration on it.
If you are interested, Racket is a pretty good resource for understanding recursion. You can check out University of Waterloo tutorial on Racket. It can give you a brief introduction to recursion in an easy to understand way, as well as walking you through some examples to understand it better.
You don't need to keep a largest variable outside your method - that's generally not a good practice with recursion which should return all context of the results.
When you think about recursion try to think in terms of a simple base case where the answer is obvious and then, for all other cases how to break it down into a simpler case.
So in pseduo-code your algorithm should be something like:
func largest(int[] array)
if array has 1 element
return that element
else
return the larger of the first element and the result of calling largest(remaining elements)
You could use Math.max for the 'larger' calculation.
It's unfortunate that you can't change the arguments as it would be easier if you could pass the index to start at or use lists and sublists. But your copying method should work fine (assuming efficiency isn't a concern).
An alternative to the algorithm above is to make an empty array the base case. This has the advantage of coping with empty arrays (by return Integer.MIN_VALUE):
int largest(int[] array) {
return array.length == 0
? Integer.MIN_VALUE
: Math.max(array[0], largest(Arrays.copyOfRange(array, 1, array.length)));
}
Here is working example of code with one method param
public int max(int[] list) {
if (list.length == 2) return Math.max(list[0], list[1]);
int max = max(Arrays.copyOfRange(list, 1, list.length));
return list[0] < max ? max : list[0];
}
private static int maxNumber(int[] arr,int n,int max){
if(n<0){
return max;
}
max = Math.max(arr[n],max);
return maxNumber(arr,n-1,max);
}

Sorting an array in ascending order that contains null values

I need to sort an array that contains null values ,
The null values represent invalid data that i have set to null but cannot be simply removed from the array as they represent an invalid piece of data
The null values must be kept in place i.e sort all other values except the null values
The error that is thrown is a NullPointerException on the call to Arrays.sort();
public static double getMedian(Double[] values) {
Double[] copy = Arrays.copyOf(values, values.length);
Arrays.sort(copy);
double median;
if (copy.length % 2 == 0)
median = (copy[copy.length / 2] + copy[copy.length / 2 - 1]) / 2;
else
median = copy[copy.length / 2];
return median;
}
All help and/or suggestions are greatly appreciated.
Add a comparator and then return the appropriate sign, to indicate less than, equal or greater than. For example:
class MyComparator<Double> implements Comparator {
// change value to -1 to inverse sort direction.
var direction = 1;
public int compare(Double o1, Double o2) {
int sign = 0;
if (o1 == null) {
sign = -1;
} else if (o2 == null) {
sign = +1;
} else {
sign = o1.compareTo(o2);
}
return sign * direction;
}
}
Arrays.sort(copy, new MyComparator());

Java Recursive Binomial Coeffecients using Linked Lists

There is a challenge problem in my compsci UIL class to use tail recursion to get a list of binomial coefficients for a given number . I think I am pretty close but I am having a hard time with base cases.
Following is my Code :
public static Cons binomial(int n)
{
return binomialb(n, null, 1);
}
public static Cons binomialb(int n, Cons last, int power)
{
if(n == power || n < 0)
{
return cons(1, null);
}
else if(last == null)
{
last = cons(1, cons(1, null));
return binomialb(n-1, last, power);
}
else
{
Cons lst = cons(1, null);
while(rest(last)!=null)
{
lst = cons((Integer)first(last)+(Integer)first(rest(last)), lst);
last = rest(last);
}
return binomialb(n-1,lst,power);
}
}
Right now I just get a list of (1).....
Your recursive call is always binomialb(n-1,something,power), so the only things that change are the first parameter, n, and the list. Your initial call has power = 1, so that will remain forever so. Now your first condition is
if (n == power || n < 0) {
return cons(1,null);
}
If you call it with n > 1 initially, the calls become binomialb(n-k,...,1) for k = 1, ..., n-1. Finally the call is binomialb(1,lotsOfWastedWork,1) which will happily return cons(1,null). If you initially call it with n < 1, the n < 0 will make it return the same after at most one recursive call, n = 1 immediately returns cons(1,null).
Whenever last is not null in a call, you should use it.

Categories

Resources