Every time I need to implement a comparator, I get stuck trying to remember when I should return -1 and when 1, and I have to look it up.
I mean, obviously -1 is less, so it implies that first is less than second. But whenever I say that to myself, I get that nagging "are you sure?" feeling. I suspect part of my confusion comes from implementing it the other way around whenever I need a descending sort.
What do you use to remember which is which?
I use this simple "substraction" mnemonic:
first - second
So, if first is "less" than second you'll get negative result, otherwise - positive or zero if they are equal.
comparator.compare(a, b) < 0 <==> a < b
I am not sure what you mean by mnemonic. However, I have had a very similar cognitive dissonance.
I am very visual, so I use the number line (the one I was taught in grade school). I just visualize the negative numbers as "left", 0 as "center" and positive numbers as "right". That the corresponds to the truth: -1 < 0 < 1
I remember the base integer case (pseudocode):
int comparator(int a, int b) {
return a-b;
}
So if we give in a small a and a large b which is the first < last we get a negative result.
I have a more visual memory, so remembering the "structure" of that function is easy and natural for me.
I used to always check the documentation when implementing Comparator and Comparable interfaces.
Question: Compare a and b
Lets first at look ascending order since the descending order will be just the inverse of whatever we do.
Question can be translated to given two numbers a and b, how would you put them on the number line?
if a < b, then we will put a on the negative side and b on the positive side.
else if a = b then we will put both at the center (at 0)
otherwise b will be on the negative side and a will be on the positive side.
Comparator Implementation:
Here you are comparing a to b.
#Override
public int compare(MyClass a, MyClass b) { //always good to rename your variables like this to be consistent
return a.f1 - b.f1;
}
Comparable Implementation:
Here you are comparing this to other.
#Override
public int compareTo(MyClass other) { // this is same as compare(this, other)
return this.f1 - o.f1;
}
Related
Hi I have started to write a console monster game for my A Level CS Class. I have hit a road block because sometimes when I run my game, some objects are not appearing and I have deduced that is due to the objects having the same coordinates. So I have attempted to write a function to check if all of the game objects don't have the same position. All objects have a position (x,y) and the allObjects is a 2d array that I have assigned all of the objects starting positions.
private static boolean checkObjects(int[][] allObjects){
int upperBound = allObjects.length;
for(int i = 0; i < upperBound -1 ; i++){
if(allObjects[i] == allObjects[i+1]){
return true;
}
}
return false;
}
Arrays in java are quite low-level things. You should probably use them here (it's a game, and List<Integer> is vastly less efficient than int[]. Maybe Project Valhalla will change that, but it'll be quite a few years before PV makes it into main java, so that's no solution and probably you can't afford to wait until it is). But, be aware of that.
They are objects. Thus, allObject[i], which returns the int[] at position i, is an object reference, and == between object references just compares the reference.
Imagine a newspaper. I'm the paperboy and I thus have 2 identical newspapers in my hands. I show you both of them and ask you: Hey, are these two equal?
Philosophically, two answers are available, both are equally correct, it's just a matter of perspective:
Yes: Both newspapers have the same number of pages and each page has the same letters. They are identical.
No: They are two different objects. Had you given me a newspaper right now and then later asked me: Hey, is this newspaper the same one as what I showed you before - then I might say 'yes', but 2 different newspapers clearly aren't identical.
In java, == is like the latter one. Let's see it in practice: (Copy this code over, compile it, run it, play around with it):
int[] a = new int[] {1, 2, 3};
int[] b = new int[] {1, 2, 3};
System.out.println(a == b); // prints false
System.out.println(Arrays.equals(a, b)); // prints true
The utility method equals(int[] a, int[] b) from the java.util.Arrays class will get you the first notion (2 separate int arrays are equal if they are the same size and contain the same int at every position).
Presumably you want Arrays.equals(allObjects[i], allObjects[i + 1]) here.
Also note that your method does this:
It goes through each adjacent pair of objects, where 'an object' is defined by an int array. So, if you have [A, B, C, D] where each letter is an int array, your code first compares A/B, then compares B/C, and then compares C/D.
The moment it hits a pair that is equal, it returns true.
It returns false only if every consecutive pair is non-equal.
In particular, if A and B are equal but B and C are not, it still returns true.
It never compares A and C.
This doesn't appear to match what you wrote. You said:
So I have attempted to write a function to check if all of the game objects don't have the same position.
If you want to check if all objects are identical, flip the loop around. You want to return false immediately if any consecutive pair is non-equal, and return true; at the end of the loop, which you only get to if every pair-wise comparison concluded: These 2 are equal.
If you want to check merely if any 2 objects are identical, then your code as written doesn't work either. What if A and C are identical, after all?
Doing a cross-cut comparison gets pricey if you have a lot of objects (if you have 100 objects, you need 100+99+98+97+.... comparisons, i.e. 0.5 * n * n objects. The time you need to do this grows squared relative to the number of objects in the system). There are efficient ways to do this, for example, if you can establish a strict sorting order, or using hashmaps. However, int[] is not a suitable data type on its own for such jobs, as int[] does not have a hashCode() implementation that is suitable for this task, and doesn't have an equals() that is suitable either. You'd have to do quite a bit more work.
If you never have more than, say, 1000 objects, a double loop is probably okay.
I had a final exam of OOP 1 (we use Java) at university back in december, and I did not pass. The thing was that I had to sort something in a kinda-specific way, and I can't figure out how to properly implement this. I will translate just a part of the exercise (I will do it with help of Google Translate):
"... John loves natural numbers, and he likes mostly the even numbers other than the odd numbers. Inside each subset, he prefers the smallest ones."
HERE is the original exercise (in spanish)
OK, so, I have to do this inside a class called Natural, and I have to be able to sort it in that custom way (described above). This is which I am not able to do. I know (a teacher told me after the exam) that I had to implement Comparable<T>.
(I know this part) After that, I had to instantiate a LinkedList<Natural>, read numbers from a file, sort them and put them (having being sorted) into another file.
Sorry if this is confusing, my English is really bad.
This is what I have in my class Natural:
public class Natural implements Comparable<Natural> {
public Integer numNatural;
public int compareTo(Natural otroNatural) {
Integer numNatural2 = ((Natural) otroNatural).numNatural;
if (this.numNatural > numNatural2) return 1;
else if (this.numNatural < numNatural2) return -1;
else return 0;
}
How can I make my program to understand that I need to put first the even numbers, and inside the even numbers, the smallest ones? After that, the smallest odd numbers should be sorted also.
You have several cases, and it would help to consider these individually.
even number vs even number
even number vs odd number
odd number vs even number
odd number vs odd number
For the second and third case you can already return 1/-1 as you know the answer without further logic. For the other two cases you need to compare as you've already shown in your answer.
I wrote something like
#Override public int compareTo(Cuboid that) {
return -ComparisonChain.start()
.compare(this.d0, that.d0)
.compare(this.d1, that.d1)
.compare(this.d2, that.d2)
.result();
}
To reverse the order, I simply negated the result, but now I see it was wrong as the docs says
Ends this comparison chain and returns its result: a value having the
same sign as the first nonzero comparison result in the chain, or zero if
every result was zero.
So Integer.MIN_VALUE is an allowed return value and then the negation fails. In the source code, I can see that nothing but -1, 0, and +1 gets ever returned, but this isn't something I'd like to depend on.
Instead of the negation I could swap all the operands. Simple and ugly, but I'm curious if there's a better solution.
One option that may be more clear than reversing the compare arguments would be to compare each pair of arguments with the reverse of their natural ordering:
.compare(this.d0, that.d0, Ordering.natural().reverse())
I don't know if that's better (personally I don't like to involve floating point operations), but you could send it through Math#signum:
return -Math.signum( .... );
I'd probably just swap the operands.
Maybe this?
int temp = ComparisonChain.start()
.compare(this.d0, that.d0)
.compare(this.d1, that.d1)
.compare(this.d2, that.d2)
.result();
return temp == Integer.MIN_VALUE ? Integer.MAX_VALUE : -temp;
There's actually a signum function using no floating point, namely Integer#signum(int) and it's about 3.5 times faster then Math.signum with the cast to double.
Out of curiosity, the fastest solution is
return -((x&1) | (x>>1));
but only by about 10%.
I'm doing some basic computation using the Apache Commons Library, and I have a 2x2 symmetric RealMatrix for which I need to compute the EigenDecomposition. The matrix is as follows:
{{10.387035702893005, 0.14862451664049367},
{0.14862451664049442, -5.1952457826500815}}
The top right and bottom left elements, of type double, are supposed to be identical, and you'll notice that they almost are. When I pass the matrix to a new instance of EigenDecomposition, however, I'll get an exception. isSymmetric() evaluates false, and because the constructor passes in 'true' as a parameter, the isSymmetric() method raises an exception. I basically need to bypass this check. What are my options? Thanks!
public EigenDecomposition(final RealMatrix matrix,
final double splitTolerance) {
if (isSymmetric(matrix, true)) {
transformToTridiagonal(matrix);
findEigenVectors(transformer.getQ().getData());
}
}
N.B. The split tolerance parameter, which one might think specifies a tolerance level, is merely a dummy parameter.
The problem seems to be a numerical error - the values are almost identical, but not exactly. A quick and dirty solution could be:
Check if the two values equal each other using the condition: Math.abs(matrix[0][1] - matrix[1][0]) < DELTA. where DELTA is your tolerance factor (what is the maximum you can tolerate so the matrix will be considered symetric).
If it is - assign matrix[0][1] = matrix[1][0]
It is easy to see that a matrix that suffices the condition should now be symetric by definition.
Can you override isSymmetric and then get the second paramter to be ignored. YOu could then call your own isSymmetric method
For example
#override
public boolean isSymmetric(RealMatrix m, Boolean b) {
return _isSymmetric(m);
}
where _isSymmetric(m) is your own implementation. You could then compare the double values in any way you see fit. I would recommend using delta rather than a straight == as double values are very rarely exactly equaly but usually are equal enough ;)
If the two values are supposed to be equal, can you just copy one over the top of the other?
matrix[0][1] = matrix[1][0];
Can anybody explain how this function works?
public int TestAdd(int a,int b) {
if(a <1)return b;
return(TestAdd((a&b)<<1,a^b));
}
Adding two matching set binary digits is equivalent to setting the next bit up: 1+1=2, and so on. So the function does that for all matching bits, then carries the unmatched ones over to another round. When no unmatched ones remain, it's done.
Since you can obviously test to see that it does indeed add two numbers, I assume you aren't understanding what those symbols are doing. Java's operators are described here:
http://download.oracle.com/javase/tutorial/java/nutsandbolts/operators.html
And you can easily look up the definitions of "logical AND" and "bitwise exclusive OR" and how they apply to ints.
Here we using the concept of recursion, this function call itself as values-
1 bit left shift of binary(Due to carry while adding) addition of numbers and xor of numbers until the a become <1.
Thus it returns the addition of numbers.
You can debug the function by taking some values for better understanding.