Reputation: 807
I Tried to do custom Ordering in my TreeMap based on length of string. Why am I getting only one Key if the length of the string is same despite being different strings.
How do I fix this and what are the implications for the equals meth0d, will it ever be used or will compareTo take its place.
The code:
import java.util.Comparator;
import java.util.Map;
import java.util.TreeMap;
public class Student implements Comparable {
int RollNo;
String Name;
public Student(int RollNo, String Name) {
this.RollNo = RollNo;
this.Name = Name;
}
public int compareTo(Object arg0) {
Student str = (Student) arg0;
return Integer.valueOf(str.Name.length()).compareTo(Integer.valueOf(this.Name.length()));
}
public static void main(String[] args) {
Map<Student, Integer> mp = new TreeMap<Student, Integer>();
mp.put(new Student(1, "Sameer"), 1);
mp.put(new Student(2, "Aameer"), 2);
for(Student st : mp.keySet()){
System.out.println((st.Name));
}
}
}
Upvotes: 1
Views: 122
Reputation: 393841
Your compareTo
method compares the lengths of the name String
s instead of their content, so Student
s having names with same length are considered identical by the TreeMap
.
In other words, the Comparable
or Comparator
used by the TreeMap
determines both ordering and uniqueness of the keys.
You can solve the issue by ordering the TreeMap
by both name length and name content (when the lengths are equal) :
public int compareTo(Object arg0) {
Student str = (Student) arg0;
int lengthComp = Integer.valueOf(str.Name.length()).compareTo(Integer.valueOf(this.Name.length()));
if (lengthComp == 0) {
// compare names if the lengths are equal
return str.Name.compareTo(this.Name);
} else {
return lengthComp;
}
}
Besides that, it's better for your class to implement Comparable<Student>
, which will allow your compareTo
method to accept a Student
argument.
How do I fix this and what are the implications for the equals meth0d, will it ever be used or will compareTo take its place.
equals
is not used by TreeMap
, and compareTo
indeed takes its place.
Upvotes: 2
Reputation: 641
Length of string for both "Shameer" and "Aameer" are same. So java compareTo method will consider both value (considering length) are same. So both object are considered equal in sorting.
While adding a object to key in Map interface the value should be unique this violated the compareTo method. So not able to add the above values.
As you already aware that in Map interface duplicate keys is not allowed.
I have explained with the simple example. If key value are same then you cannot add the values into Map interface.
import java.util.Map;
import java.util.TreeMap;
public class Student2 {
public static void main(String[] args) {
Map<String, Integer> mp = new TreeMap<String, Integer>();
mp.put("Sameer", 1);
mp.put("Sameer", 2);
for(String st : mp.keySet()){
System.out.println((st));
}
}
}
Result: Sameer
Upvotes: 0
Reputation: 372
since compare() returns 0 for both keys, they are considered equal in the sorting. See https://docs.oracle.com/javase/8/docs/api/java/lang/Comparable.html to und er stand why it is strictly recommended to habe compare behaving consistent with equals(), but the bottom line is that the second key is not added since it is considered equal to the first.
The solution is to make your compare consistent with equals by adding any kind oft tie breaker. E.g., if the two strings are not equal, but habe the same length, return their lexicographic order, or compute a hash based in the actual characters.
Upvotes: 1
Reputation: 46
The answer is in TreeMap.put. With your override of compareTo method the second put does only replace the value for the key because the two strings have same length.
Upvotes: -1