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;
}
Related
I have a function and I need to change the return value based on a condition, I managed to get only one return cause the data is static while I need to make it dynamic as shown in below code
public boolean outBound(int c_x, int c_y) {
return (blackCarX > 150 && blackCarX < 690 && blackCarY > 200 && blackCarY < 500);
}
I need to say if the x or y equals a specific number, return a different output
any advice?
This is the error I am receiving for my condition:
if (c_x > 150 && c_x < 690 && c_y > 200 && c_y < 500){
return(c_x, x_y);
}
DrawCars.java:132: error: ')' expected return(c_x, x_y) ^
DrawCars.java:132: error: not a statement return(c_x, x_y) ^
DrawCars.java:132: error: ';' expected return(c_x, x_y)
You can use if else statement
public boolean outBound(int c_x, int c_y) {
if(blackCarX > 150){
return a;
} else if (blackCarX < 690){
return b;
}
}
if you have only 2 values you can also use ? statement
public boolean outBound(int c_x, int c_y) {
return blackCarX > 150 ? a : b;
}
You need to use an if-else statement
or,
the ?: operator
Your question is not clear on how you want to use c_x or c_y so I'm making my own little example below.
For instance,
if-else statement
if(a > b) {
return i;
} else {
return j;
?: operator
(a > b) ? return i : return j // This does same thing as 1.
I have to write a method which returns true if three 3s are present in an integer array(provided they are not consecutive).
I have written this code here: However, it is returning true (which it should not do). Can someone point out my mistake?
arr[]={{4,3,5,2,3,3};
Also, this is a linear algorithm. Can it be done better?
public static boolean consecutiveThree(int[] arr) {
int x=0;
for(int i=0;i<arr.length-1;i++) {
if((arr[i]!=3 && arr[i+1]==3) || (arr[i]==3 && arr[i+1]!=3)) {
x++;
//continue;
}
if(x==3)
return true;
}
return false;
}
You said:
returns true if three 3s are present in an integer array(provided they are not consecutive)
I interpret that as having at least three 3s, and no two 3s are adjacent.
public static boolean hasThreeNonconsecutiveThrees(int... values) {
int count = 0, streak = 0;
for (int value : values) {
if (value != 3)
streak = 0;
else if (++streak == 2)
return false; // Found two consecutive (adjacent) 3s
else
count++;
}
return (count >= 3);
}
Test
System.out.println(hasThreeNonconsecutiveThrees(4,3,5,2,3,3)); // false
System.out.println(hasThreeNonconsecutiveThrees(4,3,5,3,2,3)); // true
System.out.println(hasThreeNonconsecutiveThrees(1,2,3,4,3)); // false
System.out.println(hasThreeNonconsecutiveThrees(4,3,5,3,3,3)); // false
Output
false
true
false
false
At worst case the correct array will end with ... 3 3 X 3. Unless the array is somewhat sorted or somewhat special you will have to look at every single element to reach the last three 3s. If the array is random, you need linear complexity since you have to review every single element in the array.
Your algorithm is not checking the whether arr[i-1] is '3'. That is your algorithm's mistake.
Try this:-
public static boolean consecutiveThree(int[] arr) {
int x = 0;
for (int i = 0; i < arr.length; i++) {
if (arr[i] == 3) {
if (i == 0) { // zero 'th element do not have arr[i-1].
if(arr[i + 1] != 3) {
x++;
}
} else if (i == arr.length - 1) { // last element do not have arr[i+1].
if((arr[i - 1] != 3)) {
x++;
}
} else if ((arr[i + 1] != 3) && (arr[i - 1] != 3)) {
x++;
}
}
if (x == 3) // may be x >= 3
return true;
}
return false;
}
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
}
I dont see how it is not transitive, please someone suggest me the right way.
if both values are null
I return 0, the two other statements are pretty obvious.
Why i got IllegalArgumentException with:
Comparison method violates its general contract
My compare method: (I compare doubles)
#Override
public int compare(HashMap<String, String> lhs, HashMap<String, String> rhs) {
double dist1 = 0;
double dist2 = 0;
int compInt1 = 0;
int compInt2 = 0;
if (lhs.get("dist") != null && rhs.get("dist") != null && !lhs.get("dist").equals("") && !rhs.get("dist").equals("")) {
dist1 = Double.parseDouble(lhs.get("dist").substring(0, lhs.get("dist").length() - 3));
dist2 = Double.parseDouble(rhs.get("dist").substring(0, rhs.get("dist").length() - 3));
dist1 = dist1 * 100;
dist2 = dist2 * 100;
compInt1 = (int) dist1;
compInt2 = (int) dist2;
}
if (compInt1 < compInt2) {
return -1;
} else if (compInt1 >= compInt2) {
return 1;
} else {
return 0;
}
}
Look at this code:
if (compInt1 < compInt2) {
return -1;
} else if (compInt1 >= compInt2) {
return 1;
} else {
return 0;
}
How do you expect that ever to return 0? What values of compInt1 and compInt2 would make both if conditions fail?
This violates symmetry too - it means that compare(x, y) and compare(y, x) can both return 1...
Assuming you're really just trying to compare compInt1 and compInt2 in the obvious way at this point, just replace the whole block with:
// As of Java 7...
return Integer.compare(compInt1, compInt2);
If you're using Java 6 (or earlier) you could use:
return Integer.valueOf(compInt1).compareTo(compInt2);
That's a little inefficient, but it's at least worth using to start with, just to get everything working.
Additionally, I'd strongly recommend extracting the lhs.get("dist") and rhs.get("dist") expressions from your first part - it's horribly repetitive at the moment. And just declare dist1 and dist2 within the block - they're not used elsewhere.
The condition else if (compInt1 >= compInt2) is ambiguous as it would return a value of 1 even if both values are equal. Replace your comparison logic of ints as follows :
return compInt1 - compInt2;
Transitivity defines as :
compare(a, b) == -compare(b, a)
Which implies compare(a, a) == -compare(a, a) == 0
Now, considering your code,
compare(a, a) == 1
I'm trying to create an Comparator on my custom type.
Type {
int state = 0; // can be 0 or 1
String name = ""; // can be anything
}
I'm trying to sort the list so, that at first, on the top of list are items with one state and on the bottom the other state.
And in second step, items in both section (section 1: state 0, section 2: state 1), are sorted alphabetically.
I've tried this:
#Override
public int compare(Type i1, Type i2) {
boolean a = i1.state == 1;
boolean b = i2.state == 1;
if (a && b) {
return i1.name.compareTo(i2.name);
} else if (a && !b) {
return 1;
} else {
return -1;
}
}
But item's get kind of randomized with each item state change.
List with these items:
name : A B C D E F G H I J K
state: 1 0 1 1 0 1 0 0 1 1 0
should be listed like this:
B 0
E 0
G 0
H 0
K 0
A 1
C 1
D 1
F 1
I 1
J 1
Have anybody an idea how to solve it?
Thanks
Your code breaks when both states are equal to zero. You could fix it by using this condition
if (a == b) ...
instead of
if (a && b)
...or try this instead:
#Override
public int compare(Type i1, Type i2) {
int res = i1.state - i2.state;
if (res == 0) {
return i1.name.compareTo(i2.name);
} else {
return res;
}
}
Why don't you implement Comparable and put the same logic in the compareTo method?