Comparison method violates its general contract in sorting method - java

I get an error in my sorting method.
Comparison method violates its general contract
This is my sorting object with sort method
public abstract class ComparablePerson extends IDValueItem implements
Comparable<ComparablePerson> {
private int score;
private String itemID,itemName;
//setters and getters
public int compareTo(ComparablePerson another) {
if (score == another.getScore())
return this.getItemName().compareToIgnoreCase(another.getItemName());
else if ((score) > another.getScore())
return 1;
else
return -1;
}
#Override
public boolean equals(Object o) {
final ComparablePerson other = (ComparablePerson) o;
if (score == other.getScore() && this.getItemName().equalsIgnoreCase(other.getItemName()))
return true;
else
return false;
}
I just call
Collections.sort(ComparablePersonCollection);
What can be the cause of this?

The compareTo and equals method implementations seem to be inconsistent, the error is telling you that for the same two objects equals gives true while compareTo does not produce zero, which is incorrect. I suggest you invoke compareTo from equals to ensure consistency or otherwise define a custom Comparator<T>.
Simply do:
public abstract class ComparablePerson extends IDValueItem implements Comparable<ComparablePerson> {
private int score;
private String itemID,itemName;
//setters and getters
public int compareTo(ComparablePerson another) {
if (score == another.getScore())
return this.getItemName().compareToIgnoreCase(another.getItemName());
else if ((score) > another.getScore())
return 1;
else
return -1;
}
#Override
public boolean equals(Object o) {
return compareTo(o) == 0;
}
}

ComparablePerson is abstract, the comparison method is probably overloaded elsewhere...
Can you post the client (which owns the collection) and the concrete classes?
This code works well:
public class ComparablePerson implements Comparable< ComparablePerson > {
public ComparablePerson( int score, String name ) {
_score = score;
_itemName = name;
}
#Override public int compareTo( ComparablePerson another ) {
int delta = _score - another._score;
if( delta != 0 ) return delta;
return _itemName.compareToIgnoreCase( another._itemName );
}
#Override public boolean equals( Object o ) {
return 0 == compareTo((ComparablePerson)o);
}
#Override public int hashCode() {
return super.hashCode();
}
private final int _score;
private final String _itemName;
public static void main( String[] args ) {
List< ComparablePerson > oSet = new LinkedList<>();
oSet.add( new ComparablePerson( 5, "x" ));
oSet.add( new ComparablePerson( 5, "y" ));
oSet.add( new ComparablePerson( 5, "z" ));
oSet.add( new ComparablePerson( 6, "x" ));
oSet.add( new ComparablePerson( 6, "y" ));
oSet.add( new ComparablePerson( 6, "z" ));
Collections.sort( oSet );
System.err.println( "Ok" );
}
}

Related

Java HashSet doesn't add two objets with same hashCode and equals (OK) but contains() says second object is not in set

I have a test for testing that adding the same Edge (Arista) but with the same vertices (but flipped order) is the same (this is not a directed graph).
And this is strange because the two first assertions passes OK (adding Edge1 and Edge2 will result in edges.sizes = 1 because they are the same, theoretically).
But then when testing that edges.contains(Edge2) returns false.
Why could it have worked when testing addition (to not add it duplicated) but does not work when testing contains()?
This is the code:
#Test
public final void testAristaWithSameVerticesIsNotAddedTwice() throws Exception {
Grafo grafo = new Grafo();
Vertice vertice1 = new Vertice("Vertice 1");
Vertice vertice2 = new Vertice("Vertice 2");
grafo.agregarVertice(vertice1);
grafo.agregarVertice(vertice2);
Arista arista = new Arista(vertice1, vertice2, 10);
Arista arista2 = new Arista(vertice2, vertice1, 10);
grafo.agregarArista(arista);
grafo.agregarArista(arista);
assertEquals(1, grafo.getAristasQuantity());
assertTrue(grafo.hasArista(arista));
assertTrue(grafo.hasArista(arista2)); // fails here
}
Grafo class:
private HashSet<Arista> aristas;
public boolean hasArista(Arista arista) {
return this.aristas.contains(arista);
}
Arista class
package entities;
public class Arista {
protected Vertice vertice1;
protected Vertice vertice2;
protected int peso;
public Arista(Vertice vertice1, Vertice vertice2, int peso) {
this.vertice1 = vertice1;
this.vertice2 = vertice2;
this.peso = peso;
}
public Vertice getVertice1() {
return vertice1;
}
public Vertice getVertice2() {
return vertice2;
}
public int getPeso() {
return peso;
}
public void setPeso(int peso ) {
this.peso = peso;
}
public int hashCode() {
return vertice1.hashCode() + vertice2.hashCode();
}
public boolean equals(Arista arista) {
if (arista == this) {
return true;
}
if ((arista.getVertice1() == this.vertice1 && arista.getVertice2() == this.vertice2)
|| (arista.getVertice2() == this.vertice1 && arista.getVertice1() == this.vertice2)) {
return true;
}
return false;
}
}
I found out that the equals() wasn't overriding the parent definition because it was not well defined. So it wasn't being called.
Correct way is:
#Override
public boolean equals(Object object) {
if (object instanceof Arista) {
Arista arista = (Arista) object;
if (arista == this) {
return true;
}
if ((arista.getVertice1() == this.vertice1 && arista.getVertice2() == this.vertice2)
|| (arista.getVertice2() == this.vertice1 && arista.getVertice1() == this.vertice2)) {
return true;
}
}
return false;
}

Sort Object on the basis of parameter in java

I have a java Class SalesDataJson as shown below. The different status values are 'READY', 'PICKED' and 'PACKED'.
SalesDataJson.java
public class SalesDataJson {
private Long salesOrderNumber;
private String status;
}
Now i want to order the 'SalesDataJson' object in the order of the status 'READY','PICKED' and 'PACKED'. Can anyone please help me with this.
I have the done the below code but it is not working:-
public void sort(){
Collections.sort(salesDataJsons, new Comparator<SalesDataJson>() {
#Override
public int compare(SalesDataJson o1, SalesDataJson o2) {
if (o1.getStatus() == PackagingStatus.RTW && o2.getStatus() == PackagingStatus.PICKED)
return -1;
else if (o1.getStatus() == PackagingStatus.PICKED && o2.getStatus() == PackagingStatus.RTW)
return 1;
else if (o1.getStatus() == PackagingStatus.RTW && o2.getStatus() == PackagingStatus.PACKED)
return -1;
else if (o1.getStatus() == PackagingStatus.PACKED && o2.getStatus() == PackagingStatus.RTW)
return 1;
else if (o1.getStatus() == PackagingStatus.PICKED && o2.getStatus() == PackagingStatus.PACKED)
return -1;
else if (o1.getStatus() == PackagingStatus.PACKED && o2.getStatus() == PackagingStatus.PICKED)
return 1;
return 0;
}
});
}
Make a helper method like this:
int getSortOrder(String status) {
switch(status) {
case PackagingStatus.RTW: 1; break;
case PackagingStatus.PICKED: 2; break;
case PackagingStatus.PACKED: 3; break;
default:
throw new RuntimeException("Unknown status" + status);
}
}
then you can do
new Comparator<SalesDataJson>() {
#Override
public int compare(SalesDataJson o1, SalesDataJson o2) {
return Integer.compare(getSortOrder(o1.getStatus), getSortOrder(o2.getStatus)));
}
}
If your PackagingStatus enum is defined in this way (ordered the way you like):
public enum PackagingStatus{
RTW, PICKED, PACKED;
}
you could just use ordinal() which returns the position in the enumeration.
public void sort(){
Collections.sort(salesDataJsons, new Comparator<SalesDataJson>() {
#Override
public int compare(SalesDataJson o1, SalesDataJson o2) {
return (o1.getStatus().ordinal() - o2.getStatus().ordinal());
}
});
}
Anyway, this is not really recommended since it is brittle, a small re-ordering could break your sorting.
You could attach this sorting logic in a helper class (as #Stephen Friedrich) suggested or directly into the enum itself (even if using a String status is again not ideal, I would replace it with PackagingStatus directly):
public enum PackagingStatus {
PICKED(1), PACKED(2), RTW(3);
PackagingStatus(int position) {
this.position = position;
}
private final int position;
public int getPosition() {
return position;
}
}
Then the sort becomes:
public void sort(){
Collections.sort(salesDataJsons, new Comparator<SalesDataJson>() {
#Override
public int compare(SalesDataJson o1, SalesDataJson o2) {
return (o1.getStatus().getPosition() - o2.getStatus().getPosition());
}
});
}
Of course, if you'd like to write and call the sort using java8, this is the equivalent using lambda expressions:
Collections.sort(
salesDataJsons,
(o1, o2) ->
o1.getStatus().getPosition() - o2.getStatus().getPosition()
);
You just arrange the statuses in the order you like and
then your sorting comes easy as this:
List<SalesDataJson> sortedList = orignalList.stream()
.sorted(Comparator.comparing(SalesDataJson::getStatus))
.collect(Collectors.toList());

my deterministic turing machine won't work, because my equals and indexof method throw no source error

I have the problem, that my equals method doesnt work as i want it to. I want to implement a deterministic turing machine, so I want to add the method findCommand(), which searchs through a arraylist of commands. So I decided to create a searchDummy to find all Transitions that are available for the Configuration I have.
Class States:
public class States {
private int stateId;
private boolean rejState;
private boolean accState;
private boolean stopState;
private List<Commands> commands = new ArrayList<Commands>();
equals in class States:
#Override
public boolean equals(Object other) {
if (this == other) {
return true;
} else if (other instanceof States) {
States otherState = (States) other;
return (stateId == otherState.stateId);
} else {
return false;
}
}
hashCode:
#Override public int hashCode() {
StringBuilder b = new StringBuilder(stateId);
return b.toString().hashCode();
}
this is the findCommand method in States:
public Commands findCommand(States state, char inputTapeChar,
char[] tapeChars) {
Commands searchDummy = new Commands(state, inputTapeChar, tapeChars,
null, null, null, null);
int pos = commands.indexOf(searchDummy);
return pos >= 0 ? commands.get(pos) : null;
}
commands is my arraylist, so I want to find the searchDummy with indexOf().
I have the class Commands, which holds the attribute Configuration configuration, the class Configuration, which holds the attributes of a Configuration and the attribute Transition transition and the class transition that holds the attributes for itself.
Class Commands:
public class Commands implements Comparable<Commands> {
private Configuration configuration;
Class Configuration:
public class Configuration {
private Transition transition;
private States state;
private char inputTapeChar;
private char[] tapeChars;
Class Transition:
public class Transition {
private States targetState;
private Direction inputTapeHeadMove;
private char[] newTapeChars;
private Direction[] tapeHeadMoves;
i have this equals method in Commands:
#Override public boolean equals(Object other) {
if (this == other) {
return true;
} else if (other instanceof Commands) {
Commands otherCmd = (Commands) other;
return (configuration.equals(otherCmd.configuration));
} else {
return false;
}
}
and this hashcode
#Override
public int hashCode() {
StringBuilder b = new StringBuilder(configuration.getState() + ","
+ configuration.getInputTapeChar());
for (char c : configuration.getTapeChars()) {
b.append("," + c);
}
return b.toString().hashCode();
}
then almost the same in Configuration:
#Override
public boolean equals(Object other) {
if (this == other) {
return true;
} else if (other instanceof Configuration) {
Configuration otherConfi = (Configuration) other;
return (state.equals(otherConfi.state))
&& (inputTapeChar == otherConfi.inputTapeChar)
&& (Arrays.equals(tapeChars, otherConfi.tapeChars));
} else {
return false;
}
}
hashcode:
#Override
public int hashCode() {
StringBuilder b = new StringBuilder(state + "," + inputTapeChar);
for (char c : tapeChars) {
b.append("," + c);
}
return b.toString().hashCode();
}
equales in class State:
#Override
public boolean equals(Object other) {
if (this == other) {
return true;
} else if (other instanceof States) {
States otherState = (States) other;
return (stateId == otherState.stateId);
} else {
return false;
}
}
so my question:
when I debug this it goes through until it's finished with the checks but when it should return the value it stucks at Configuration.equals(...) and shows the error no source found!
what is the problem? Are the hashcodes wrong? Or are the equals wrong?
I never used equals before so I dont know when i need to use it or how i need to fix this. thanks for your help.
Your hashCode implementation looks suspect - all that String stuff is not standard.
For example for your Transition class should be something like this:
#Override
public int hashCode() {
int result = 17;
result = 31 * result + targetState.hashCode();
result = 31 * result + inputTapeHeadMove.hashCode();
result = 31 * result + newTapeChars.hashCode();
result = 31 * tapeHeadMoves.hashCode();
return result;
}
Most IDEs will offer autogen of hashCode and equals methods.

How to compare three integer values?

I have three integer values along with its text. My requirement is to give rank to all of them.
E.g. I have A = 50 points, B = 500 Points, C = 50 points.
Now I would like to compare all of these and find max and equal values and its according name(like, A/B/C).
EDIT ::
As a output it should return, B = 1st Rank, A = 2nd Rank, C = 2nd Rank.
If anyone has any idea about how can I implement code as per my requirement then, it would be great.
Thanks in advance.
public class ScoreVO implements Comparator<Integer> {
private String playerName = Constants.BLANK_STRING;
private int playerScore;
public String getPlayerName () {
return playerName;
}
public void setPlayerName ( String playerName ) {
this.playerName = playerName;
}
public int getPlayerScore () {
return playerScore;
}
public void setPlayerScore ( int playerScore ) {
this.playerScore = playerScore;
}
#Override
public int compare ( Integer o1, Integer o2 ) {
return o2.compareTo ( o1 );
}
}
Here is my class with Comparator<>.
Please suggest me if I am wrong.
A sample running code which gives output shown below as per your requirement along with player rank. There is a separate method assignRank(List<>) which you can use to assign ranks to players.
Score List: [ScoreVO [playerName=B, playerScore=500, playerRank=1], ScoreVO [playerName=A, playerScore=50, playerRank=2], ScoreVO [playerName=C, playerScore=50, playerRank=2]]
public class ScoreExample {
public static void main(String[] args) {
List<ScoreVO> scoreList = new ArrayList<ScoreVO>();
scoreList.add(new ScoreVO("A", 50));
scoreList.add(new ScoreVO("C", 50));
scoreList.add(new ScoreVO("B", 500));
Collections.sort(scoreList);
assignRank(scoreList);
System.out.println("Score List: "+scoreList);
}
private static void assignRank(List<ScoreVO> scoreList) {
int rank = 0;
int score = 0;
for(ScoreVO scoreVO : scoreList) {
if(score != scoreVO.getPlayerScore()) {
rank++;
scoreVO.setPlayerRank(rank);
score = scoreVO.getPlayerScore();
} else {
scoreVO.setPlayerRank(rank);
}
}
}
}
class ScoreVO implements Comparable<ScoreVO> {
public String playerName;
public int playerScore;
public int playerRank;
public ScoreVO(String playerName, int playerScore) {
this.playerName = playerName;
this.playerScore = playerScore;
}
public String getPlayerName() {
return playerName;
}
public void setPlayerName(String playerName) {
this.playerName = playerName;
}
public int getPlayerScore() {
return playerScore;
}
public void setPlayerScore(int playerScore) {
this.playerScore = playerScore;
}
public int getPlayerRank() {
return playerRank;
}
public void setPlayerRank(int playerRank) {
this.playerRank = playerRank;
}
#Override
public int compareTo(ScoreVO o) {
if(o.getPlayerScore() != getPlayerScore()) {
if(getPlayerScore() > o.getPlayerScore())
return -1;
else
return 1;
}
return getPlayerName().compareTo(o.getPlayerName());
}
#Override
public String toString() {
return "ScoreVO [playerName=" + playerName + ", playerScore="
+ playerScore + ", playerRank=" + playerRank + "]";
}
}
ScoreVO should implement Comparable<ScoreVO>. And your compareTo method looks like this:
#Override
public int compareTo ( ScoreVO o ) {
if(playerScore != o.playerScore)
return Integer.compare(playerScore, o.playerScore);
return playerName.compareTo(o.playerName);
}
You should implment Comparable for ordering purpuses, and equals() for equation (that can use compareTo)
like this
public class ScoreVO implements Comparable<ScoreVO> {
#Override
public int compareTo(ScoreVO other) {
return other == null ? 1 : getPlayerScore() - other.getPlayerScore();
}
#Override
public boolean equals(object other) {
return !(other instanceof ScoreVO) ? false : compareTo(other) == 0 ;
}
}
However, you probably want to compare equality based on player name. think of putting ScoreVO object in a map - what is the key? so -
#Override
public boolean equals(object other) {
return other == null || !(other instanceof ScoreVO) ? false :
getPlayerName.equals(other.getPlayerName()) ;
}
As there are just three values, it is possible to hard-code all operations. You can think of a very compact and efficient way to work this out.
Every comparison of two values can give an outcome >, = or <. Assigning the value 0, 1 or 2 to these, you can pack the three comparisons in a single number using base 3 encoding. You will end up with a number in range 0 to 26, and every different value corresponds to a different answer that you can tabulate (or process in a switch statement).
int Compare(int A, int B) { return A > B ? 0 : (A == B ? 1 : 2); }
char* Answer[27]= { "A1B2C3", "A1B1C3", "B1A2C3", ... }; // To be filled
return Answer[Compare(A, B) + 3 * compare(B, C) + 9 * compare(A, C)];

Java Comparable, mutliple/different implenetations of compareTo() method

I have this class:
public class Sample implements Comparable<Sample> {
public String a;
public String b;
public String c;
public int compareTo (Sample sampleToCompare) {
int compResult = this.a.compareTo(sampleToCompare.a);
return (compResult != 0 ? compResult :
this.b.compareTo(sampleToCompare.b));
}
}
I want compareTo() to behave or sort using different class properties depending if a flag is set.
So, if flag == 1 I'd like compareTo() to using property c, otherwise is flag == 0, whatever is currently in the method.
In other words, sort the same class in different ways.
I am not sure how to achieve this. Please help.
Also, please let me know if more information is needed from my side.
If you want to implement different kind of sorting, you should take a look at java.util.Comparator interface.
public class SampleComparatorA implement Comparator<Sample> {
public int compare(Sample a, Sample b) {
// Your sorting
}
}
And use java.util.Collections.sort() method with the Comparator as the secound parameter instead.
Collections.sort(aSampleList, new SampleComparatorA());
How about:
public int compareTo(Sample sampleToCompare) {
if (flag == 1) {
return this.c.compareTo(sampleToCompare.c);
}
if (flag == 0) {
// current stuff
}
...
}
That's not a very object-oriented way to do it, though. Probably you should have two different comparators and a way to select them based on your "flag" value. Something like:
class Sample {
private String a;
private String b;
private String c;
}
class ASampleComparator implements Comparator<Sample> {
public int compare(Sample o1, Sample o2) {
return o1.a.compareTo(o2.a);
}
}
class BSampleComparator implements Comparator<Sample> {
public int compare(Sample o1, Sample o2) {
return o1.b.compareTo(o2.b);
}
}
class CSampleComparator implements Comparator<Sample> {
public int compare(Sample o1, Sample o2) {
return o1.c.compareTo(o2.c);
}
}
public Comparator<Sample> pickComparator(int flag) {
switch (flag) {
case 0:
return new ASampleComparator();
case 1:
return new BSampleComparator();
case 2:
return new CSampleComparator();
default:
throw new IllegalArgumentException("Bad flag value: " + flag);
}
}
You should make your flag static so the comparison will be consistent (as described in Effective Java, item 12), otherwise, you might get that a.compareTo(b) returns that a > b, but b.compareTo(a) returns that b > a. So the simplest implementation I can think about is:
public class Sample implements Comparable<Sample> {
public String a;
public String b;
public String c;
public static boolean my_flag = false;
public int compareTo (Sample sampleToCompare) {
if (flag) {
return this.c.compareTo(sampleToCompare.c);
}
int compResult = this.a.compareTo(sampleToCompare.a);
return (compResult != 0 ? compResult :
this.b.compareTo(sampleToCompare.b));
}
}

Categories