Sort arraylist in specific order [duplicate] - java

This question already has answers here:
Sort ArrayList of custom Objects by property
(29 answers)
Closed 7 years ago.
I have an arraylist like below:
ArrayList<PhoneNumber> arrayListToSort
PhoneNumber have following properties
private String number;
private String numberType;
Number type is like MOBILE , HOME , OFFICE
I want to sort arrayListToSort by numberType of each.
I can do this with simple alphebetical order.
But my problem is how to sort the list by follwing order.
MOBILE
HOME
OFFICE

Hey you can try PhonNumberType with enum check below code
package test;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
enum PhonNumberType {
MOBILE, HOME, OFFICE
}
class PhoneNumber implements Comparable<PhoneNumber> {
private String number;
private PhonNumberType phonNumberType;
#Override
public int compareTo(PhoneNumber o) {
return this.phonNumberType.compareTo(o.phonNumberType);
}
public String getNumber() {
return number;
}
public void setNumber(String number) {
this.number = number;
}
public PhonNumberType getNumberType() {
return phonNumberType;
}
public void setNumberType(PhonNumberType phonNumberType) {
this.phonNumberType = phonNumberType;
}
#Override
public String toString() {
return "PhoneNumber [number=" + number + ", phonNumberType=" + phonNumberType + "]";
}
}
public class T {
public static void main(String[] args) {
List<PhoneNumber> test = new ArrayList<PhoneNumber>();
PhoneNumber pn = new PhoneNumber();
pn.setNumber("1");
pn.setNumberType(PhonNumberType.HOME);
test.add(pn);
pn = new PhoneNumber();
pn.setNumber("2");
pn.setNumberType(PhonNumberType.MOBILE);
test.add(pn);
pn = new PhoneNumber();
pn.setNumber("3");
pn.setNumberType(PhonNumberType.OFFICE);
test.add(pn);
Collections.sort(test);
System.out.println(test);
}
}
output is : [PhoneNumber [number=2, phonNumberType=MOBILE],
PhoneNumber [number=1, phonNumberType=HOME], PhoneNumber [number=3,
phonNumberType=OFFICE]]

Your Ranking is no natural order.
To get your goal result, you must define your own Comparator.
By the way, as #Alexis C. says, use an Enum for your numberType

Use an enum for that:
public enum NumberType {
MOBILE,HOME,OFFICE;
}
If your PhoneNumber is comparable:
#Override
public int compareTo(PhoneNumber o) {
return numberType.compareTo(o.numberType);
}
It will follow the order described in the enum:
MOBILE,HOME,OFFICE

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Map;
public class Main {
public static void arrayListToSort(ArrayList<PhoneNumber> arrayListToSort) {
Map<String, Integer> phoneTypeToOrder = new HashMap<>();
phoneTypeToOrder.put("MOBILE", 0);
phoneTypeToOrder.put("HOME", 1);
phoneTypeToOrder.put("OFFICE", 2);
Collections.sort(arrayListToSort, new Comparator<PhoneNumber>() {
#Override
public int compare(PhoneNumber o1, PhoneNumber o2) {
if (o1 == null || o1.numberType == null) {
return -1;
}
if (o2 == null || o2.numberType == null) {
return 1;
}
Integer o1Order = phoneTypeToOrder.get(o1.numberType);
Integer o2Order = phoneTypeToOrder.get(o2.numberType);
return o1Order.compareTo(o2Order);
}
});
}
}
class PhoneNumber {
String number;
String numberType;
}

I suggest using a customing "sorting-method" called Comparator. In this Comparator you define a "value" for each your records which will be calculated at runtime. The calculation of this value is entirely up to you. You can for example define that "foo" == 1, "bar" == 2 and "john" == 654. The sorting method of Java will then ask each record for it's "value" and sort accordingly (I think using Quicksort-Algorithm, but I am not sure about this).
Here's a nice little tutorial to get you into this topic and shows how to implement Comparator and Comparable-Interfaces correctly:
http://www.tutorialspoint.com/java/java_using_comparator.htm
This one is a bit more indepth: http://www.journaldev.com/780/java-comparable-and-comparator-example-to-sort-objects
Besides: as stated before, use enums for your number-types. not because it's easier (imho) but because it is much faster comparing enums than comparing Strings.

You can use a TreeSet collection, which sorts the entries.
TreeSet<PhoneNumber> sortedList = new TreeSet<>((PhoneNumber p1, PhoneNumber p2) -> p1.compareTo(p2));
Since you have to define an order for the entries, your PhoneNumber class will have to implement the Comparable interface and you need to override the compareTo() method to say that you will compare on the numberType
public int compareTo(Object o) {
PhoneNumber p = (PhoneNumber) o;
return numberType.equals(o.getNumberType())?0:numberType.equals("MOBILE")?-1:1;
}
However, better to use an enum if you want to add more number types in future

If you make your NumberType enum, not String, its compareTo() method will return result based on order in which enum instances are declared, not alphabetical:
public enum NumberType {
MOBILE, HOME, OFFICE;
}
MOBILE now is less than HOME and HOME is less than OFFICE. Now you may sort your collection using custom comparator:
list.sort(comparing(PhoneNumber::getNumberType).thenComparing(PhoneNumber::getNumber));

There are two ways to do this.
Use a Comparator
In this approach, you sort the ArrayList using a custom Comparator.
Here is the Comparator code. Notice how it first tries to sort on numberType, and then number:
public class PhoneNumberComparator implements Comparator<PhoneNumber> {
#Override
public int compareTo (PhoneNumber lhs, PhoneNumber rhs) {
int result = lhs.numberType.compareTo(rhs.numberType);
if (result == 0) {
result = lhs.number.compareTo(rhs.number);
}
return result;
}
}
Then you can call:
Comparator c = new PhoneNumberComparator();
arrayListToSort.sort (c)
Now by itself, this won't work completely because the sort of numberType will just be in string order. The most convenient way to impose the ordering is to make numberType an enumeration. Here is the code for that:
public enum NumberType { MOBILE, HOME, OFFICE }
Then the PhoneNumber must be defined so that numberType is a NumberType:
public class PhoneNumber {
public String number ;
public NumberType numberType;
// .......
}
(By the way I would encourage you to also make number and numberType into private variables, and add getter methods, as per the JavaBeans standard.)
Make PhoneNumber Implement Comparable
If you are planning to do this sort often, then instead of writing the Comparator, you should make PhoneNumber implement the Comparable interface:
public class PhoneNumber implements Comparable <PhoneNumber> {
public String number ;
public NumberType numberType;
// .......
#Override
public int compareTo (PhoneNumber rhs) {
int result = this.numberType.compareTo(rhs.numberType);
if (result == 0) {
result = this.number.compareTo(rhs.number);
}
return result;
}
}
Then you can just call:
arrayList.sort()
You still need to make NumberType an enum, as discussed in the first approach. The above compareTo() implementation relies on NumberType being Comparable; all enum instances are automatically Comparable.
Notice the similarities and the differences between the Comparator and the compareTo() implementations. A good discussion of Comparator and Comparable can be found here.

Related

Sorting of Arraylist of Custom Object in java [duplicate]

This question already has answers here:
Sort ArrayList of custom Objects by property
(29 answers)
Closed 5 years ago.
I have a Custom Object Suppose Team
public class Team{
String name;
int teamNo;
ArrayList<Team> innerTeams;
int teamId;
//Getters and Setter Methods
Now I want to Sort it in Ascending Order of First Property name taking into account that each Team Object has a property of itself as Team as arraylist declared as innerTeams How can I be able to Sort this. So utlimately when any arrayList of object Team is present it should be sorted.
Please anyone help me with this.
The easiest way is to have your Team class implement Comparable. You can tweak the logic inside of the compareTo to match your needs, e.g. compare inner team names, etc. Then you use Collections.sort() to do the actual sorting.
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class Team implements Comparable<Team> {
String name;
int teamNo;
List<Team> innerTeams = new ArrayList<>();
int teamId;
#Override
public int compareTo(Team o) {
if(o == null) {
return 1;
} else if(name == null) {
return 0;
} else {
return name.compareTo(o.name);
}
}
public static void main(String[] args) {
Team team1 = new Team();
team1.name = "z";
Team team2 = new Team();
team2.name = "a";
List<Team> teams = new ArrayList<>();
teams.add(team1);
teams.add(team2);
System.out.println(teams);
Collections.sort(teams);
System.out.println(teams);
}
#Override
public String toString() {
return name;
}
}
Output:
[z, a]
[a, z]
You can then also use the same approach to sort innerTeams by name if needed.
You should define Comparator of Team.
class TeamComparator implements Comparator<Team>{
public int compare(Team o1,Team o2){
return o1.name.compareTo(o2.name);
}
}
And sort by Collections.sort(teamList, new TeamComparator())

How to sort a Java list of objects using a RuleBasedCollator on a field?

I want to sort an ArrayList of objects on a specific field using a given RuleBasedCollator.
For example, we have a list of Thing objects:
public Thing {
public String name;
public String type;
}
List<Thing> things = new ArrayList<Thing>();
RuleBasedCollator ruleBasedCollator = new RuleBasedCollator("< Table < Plate < Fork < Knife");
Now, after having created Thing objects and added them to the things list, I want to sort this list, getting first things of type "table" and last things of type "knife".
Does anyone know how to do it?
You can try something like this, instead of using compareTo in compare method of Comparator you can call RuleBasedCollator's compare.
mQueue.sort((o1, o2) -> {
if (o1.getDescription().getTitle() != null && o2.getDescription().getTitle() != null) {
return mRuleBasedCollator.compare(o1.getDescription().getTitle().toString(),
o2.getDescription().getTitle().toString());
} else {
return 0;
}
});
As far as I understand a RuleBaseCollator is intended for sorting Strings, at least i says so in the Collator class which is the super class. I would instead use a Comparator, something like this:
public class ThingSorter {
public enum ThingType{
//wanted sort order, sort on ordinal :
//Table < Plate < Fork < Knife
TABLE, PLATE, FORK, KNIFE
}
public static class Thing {
private String name;
private ThingType type;
public Thing(String name, ThingType tt) {
this.name = name;
type = tt;
}
public String toString() {
return name + " [" + type + "]";
}
}
public static class MyThingComparator implements Comparator<Thing> {
#Override
public int compare(Thing t1, Thing t2) {
return t1.type.ordinal() - t2.type.ordinal();
}
}
public static class MyReverseThingComparator implements Comparator<Thing> {
#Override
public int compare(Thing t1, Thing t2) {
return t2.type.ordinal() - t1.type.ordinal();
}
}
public static void main(String[] args) throws ParseException {
List<Thing> things = new ArrayList<Thing>();
things.add(new Thing("One", ThingType.KNIFE));
things.add(new Thing("Two", ThingType.FORK));
things.add(new Thing("Three", ThingType.PLATE));
things.add(new Thing("Four", ThingType.TABLE));
System.out.println("unsorted:\n" + things);
Collections.sort(things, new MyThingComparable());
System.out.println("sorted:\n" + things);
Collections.sort(things, new MyReverseThingComparable());
System.out.println("sorted:\n" + things);
}
}
The names are are not involved in the sorting in this case just the type (and the ordinal in the type)
You could certainly use the TreeMap or enum as the previous answers suggest; a rather simpler alternative is to use just a custom compatator, without the enum. If you're using Java 8 you can get it down to a single line:
Collections.sort(things,
(Thing t1, Thing t2)->ruleBasedCollator.compare(t1.type, t2.type) );
The pre-8 version would do the same thing with an anonymous Comparator
I finally found a solution using a TreeMap. I use the "type" property for the key and a list of Thing for the value. Instead of using a RuleBasedCollator, I created a ListBasedCollator extending Collator, because RuleBasedCollator rules work on characters but not on words.
public class ListBasedCollator extends Collator {
private List<String> list;
public ListBasedCollator(String[] array) {
list = Arrays.asList(array);
}
#Override
public int compare(String source, String target) {
if(!list.contains(target)) {
return 1;
}
if(!list.contains(source)) {
return -1;
}
return Integer.valueOf(list.indexOf(source)).compareTo(Integer.valueOf(list.indexOf(target)));
}
#Override
public CollationKey getCollationKey(String source) {
return null;
}
#Override
public int hashCode() {
return 0;
}
}
Here is how I construct the TreeMap:
String[] sortingList = {"TABLE", "PLATE", "FORK", "KNIFE"};
ListBasedCollator listBasedCollator = new ListBasedCollator(sortingList);
Map<String, List<Thing>> thingMap = new TreeMap<String, List<Thing>>(listBasedCollator);
So, the thingMap will always be sorted by type using the listBasedCollator.
And I can also sort alphabetically the list of things for each different type.

How to sort a list of structs by an element of the struct in java

I have a list of structs that I would like to sort according to a specific element of the struct:
private class myStruct {
public Boolean GUI;
public float CallTime;
public String ReqID;
public String ReqGUID;
public String Stereotype;
public String StereotypeGUID;
}
private List<myStruct> DataList = new ArrayList<myStruct>();
How could I sort DataList by the element "ReqID" without hardcoding it?
Is there a possibility to use Arrays.sort()?
You should use a Comparator.
class YourComparator implements Comparator<myStruct>{
public int compare(myStruct s1, myStruct s2){
//here comes the comparison logic
}
}
And then use this form of the sort() method:
Arrays.sort(T[] arrayToSort, Comparator<T> yourComparator);
It's not very clear whether you use a collection or an array as the data structure.
In case you use a List, then use Collections.sort().
For custom sorting you can implement the Comparable interface.
With this interface you create a method compareTo() which returns a negative number, 0 or a positive number. Based on the return code Collections.sort() can tell if the element has to be before or after another element.
A nice example how to use it can be found in this answer: java class implements comparable
use the Comparator interface like this
public static void main(String[] args) {
List<myStruct> DataList = new ArrayList<myStruct>();
//ADD Objects to DataList here
Collections.sort(DataList, new Comparator() {
public int compare(Object o1, Object o2) {
myStruct p1 = (myStruct) o1;
myStruct p2 = (myStruct) o2;
int ret = -1;
//business logic here
if (Integer.parseInt(p1.ReqGUID) == Integer.parseInt(p2.ReqGUID)) {
ret = 0;
} else if (Integer.parseInt(p1.ReqGUID) > Integer.parseInt(p2.ReqGUID)) {
ret = 1;
} else if (Integer.parseInt(p1.ReqGUID) < Integer.parseInt(p2.ReqGUID)) {
ret = -1;
}//end business logic
return ret;
}
});
}
Here inside the Collections.sort() method I am implementing the Comparator interface and overriding the compare() method. This will actually sort your list based on the business logic you implemented inside the compare() method;
Your class structure look strange to me.. You have public fields inside a private class..
Ideally your fields should be marked private and you can have getters and setters to access them..
As for your problem, you can take a look at two important interfaces taht are defined for this kind of job: - http://docs.oracle.com/javase/1.4.2/docs/api/java/util/Comparator.html and http://docs.oracle.com/javase/1.4.2/docs/api/java/lang/Comparable.html..
You use Comparator when you want to have multiple ways to compare your class instance..
You can just create a class implementing the Comparator interface, and pass the instance of this class to Collections.sort() method to use this Comparator for sorting..
In this case, compare() method is used to do the job of comparison.
Alternatively, you can associate only one way of comparing a class instance by making that class implementing Comparable interface.. In this case you need to override compareTo() method..
Here's a sample code using Comparator: -
public class MyComparator implements Comparator<Box> {
#Override
public int compare(Box box0, Box box1) {
int w0 = box0.getWeight();
int w1 = box1.getWeight();
return (w0 > w1? -1 : (w0 == w1) ? 0 : 1);
}
}
public class Box {
private int weight;
public Box() {
}
public Box(int weight) {
this.weight = weight;
}
public int getWeight() {
return weight;
}
public void setWeight(int weight) {
this.weight = weight;
}
}
And Your Main
public class Main {
public static void main(String args[]) {
List<Box> boxList = new ArrayList<Box>();
Collections.sort(boxList, new MyComparator());
}
}
Hope it helps..
You can define your own Comparator and use Collections.sort(), passing that Comparator in. That way you can define different comparators for searching using different fields.
Alternatively your struct can implement the Comparable interface and Collections.sort() can sort using this. This is called using the natural sort order, since it's implicit to your class.
Here's the Java tutorial on sorting and ordering.
Use java.util.Collections.sort() with a Comparator instance. See the JavaDocs.
Use Arrays.sort(T[] a, Comparator<? super T> c)
or Collections.sort(List a, Comparator c)
Simplest solution
Just implement java.lang.Comparable interface in you class like following:
class MyStruct implements Comparable<MyStruct>{
public Boolean GUI;
public float CallTime;
public String ReqID;
public String ReqGUID;
public String Stereotype;
public String StereotypeGUID;
#Override
public int compareTo(MyStruct other) {
return ReqID.compareTo(other.ReqID);
/* also you can use ReqID.compareToIgnoreCase(other.ReqID); */
}
#Override
public String toString() {
return "(" + ReqID + ")";
}
}
Override also toString() method just for printing.
Also, keep in mind that String's compareTo() method sorts using lexicographical order. In case you want numeric ID's it is better to use int or other numerical type.
Following is complete code to sort using Arrays.sort() as well as Collections.sort() - choose what suits you :)
public class MyStructSort {
private final static String[] STRUCT_IDS = {"C", "D", "A", "Aa", "B", "Z", "Aaa" };
private static List<MyStruct> createList() {
List<MyStruct> structList = new ArrayList<MyStruct>();
for (String id: STRUCT_IDS) {
MyStruct struct = new MyStruct();
struct.ReqID = id;
structList.add(struct);
}
return structList;
}
public static void main(String[] args) {
List<MyStruct> dataList = createList();
/* Sort using Lists (Collections) */
Collections.sort(dataList);
System.out.println("List sort:\t" + dataList);
/* Sort using arrays */
MyStruct[] dataArray = dataList.toArray(new MyStruct[dataList.size()]);
Arrays.sort(dataArray);
// print sorted array
System.out.print("Array sort:\t");
for (MyStruct struct: dataArray) {
System.out.print(struct+" ");
}
}
}
This is just demonstration code, so some null-checks and getters and setters would be needed to make it perfect.

Using the Comparable interface when comparing Strings

I searched for this question, but I only found one thread that was kind of confusing, so I'm going to ask here for what I hope will be a clearer answer.
I have an assignment to use the Comparable interface to sort objects in an array by customer name. I have only done this with integers so far, so I'm not sure how to compare the strings together. How would I go about that? Here is where I am so far, assuming I am to use a.name compared to this.name:
public int comparedTo(Customer a)
{
} //end comparedTo
I also need to make a class to implement the Comparator interface to sort the values based on customer purchases and I think I did that properly, but I'd like to make sure before I go ripping my hair out when it's wrong. Here is what I did for that:
class NameComparator implements Comparator{
public int compare(Object cust1, Object cust2){
String cust1Purch = ((Customer)cust1).purchase;
String cust2Purch = ((Customer)cust2).purchase;
return cust1Purch.compareTo(cust2Purch);
}
Any help is greatly appreciated!
Its all ok, but you can specify Comparator generic type and then no need to cast objects:
class NameComparator implements Comparator<Customer>{
public int compare(Customer cust1, Customer cust2){
String cust1Purch = cust1.purchase;
String cust2Purch = cust2.purchase;
return cust1Purch.compareTo(cust2Purch);
}
Here is a complete example that might help you:
A CustomerComparator:
class CustomerComparator implements Comparator<Customer> {
#Override
public int compare(Customer c1, Customer c2) {
return c1.name.compareTo(c2.name); // or, simply c1.compareTo(c2);
}
}
A Comparable Customer:
class Customer implements Comparable<Customer> {
String name;
public Customer(String name) {
this.name = name;
}
#Override
public int compareTo(Customer o) {
return name.compareTo(o.name);
}
public String toString() {
return name;
}
}
A simple test driver:
public class Test {
public static void main(String[] args) {
List<Customer> customers = Arrays.asList(new Customer("Bravo"),
new Customer("Charlie"),
new Customer("Delta"),
new Customer("Alpha"));
Collections.sort(customers);
// Or
// Collections.sort(customers, new CustomerComparator());
System.out.println(customers);
}
}
(ideone.com demo)
Looks fine. But you can utilize Generics:
class NameComparator implements Comparator<Customer> {
public int compare(Customer cust1, Customer cust2) {..}
}
I seem to get it right for the Comparable interface. Nothing really complicated there.
As for the Comparator, if you're not using generics, you also need to validate both argument for the same base type, at least Comparable since you're using that interface :
if (cust1 instanceof Comparable && cust2 instanceof Comparable) {
Comparable c1 = (Comparable) cust1;
Comparable c2 = (Comparable) cust2;
return c1.compareTo(c2);
} else {
return false;
}
1) I would use generics to define your comparator and avoid additinal class casting:
class NameComparator implements Comparator<Customer> {
public int compare(Customer cust1, Customer cust2) {
...
}
}
2) String class in java already implements Comparable interface ( http://download.oracle.com/javase/1.5.0/docs/api/java/lang/String.html ). So, if you need to just compare on customer's name or purchase string, then you can just delegate it to String and that's what you already do.

How can I order TreeMaps or ArrayLists holding Persons based on their ID, name, or birthdate?

I have tried almost everything and I can't seem to get my lists to order themselves.
Here's some code:
private List<Person> names = new ArrayList<Person>();
private Map<Integer, Person> peopleMap = new TreeMap <Integer, Person>();
for(int i = 0; i<20; i++)
{
Person personOne = new Person();
peopleMap.put(personOne.id,personOne);
names.add(personOne);
}
Collections.sort(names);
run();
}
My Person class:
public class Person implements Comparable {
public String name;
public int id;
public Date birthdate;
static int idRecord = 0;
The values are filled with randoms. My date has a date format.
I also have a toString method inside my person class, but for some reason when I try to print my maps it gives me the hashcode (this is the hashcode right?) Person#a62fc3.
Here is my toString inside the person clasS:
public String toString()
{
char tab = '\t';
return ("ID Number: "+id+tab+" Name: "+tab+name+tab+" Birthdate: "+(birthdate.toString()));
}
I should add that I am not able to call my toString method inside my person class. Because it is printing Person#a62fc3.
public void sortByID()
{
char tab = '\t';
for (int i = 1; i<20; i++)
System.out.println((peopleMap.get(i)).toString());
//System.out.println("ID Number: "+(peopleMap.get(i).id)+tab+" Name: "+tab+peopleMap.get(i).name+tab+" Birthdate: "+peopleMap.get(i).birthdate);
run();
}
The commented code will work but the code calling the toString does not print what it should
Compare to method inside of my Person class:
public int compareTo(Object obj) {
Person o = (Person) obj;
if (this.id == o.id) { return 0; }
if (this.id > o.id) { return 1; }
if (this.id < o.id) { return -1; }
return 0;
I can provide more code if it's needed.
Compare by name method and it's output. Should I make an arrayList to store my values in and then sort it in that?
public void sortByName()
{
// char tab = '\t';
for(int j = 1; j<20; j++)
{
// System.out.println("ID Number: "+(names.get(j).id)+tab+" Name: "+tab+peopleMap.get(j).name+tab+" Birthdate: "+peopleMap.get(i).birthdate);
//Person p = names.get(j);
System.out.println(names.get(j).toString());
}
}
Output:
Person#10b30a7
Person#1a758cb
Person#1b67f74
Person#69b332
Person#173a10f
Person#530daa
Person#a62fc3
Person#89ae9e
Person#1270b73
Person#60aeb0
Person#16caf43
Person#66848c
Person#8813f2
Person#1d58aae
Person#83cc67
Person#e09713
Person#de6f34
Person#156ee8e
Person#47b480
Thanks
Well, I can't pinpoint the exact problem, I have a few suggestions.
Maps aren't sorted.
In general, an Map is not sorted, so you will not be able to sort the keys of the map. If you want to sort the Map use the SortedMap interface.
Use Generics when possible
The Comparable interface is generic. You should probably be implementing Comparable<Person>
Then your compareTo() method should look like this:
public int compareTo(Person p) {
if (this.id > p.id) return 1;
else if (this.id < p.id) return -1;
else return 0;
}
The difference between Comparator<Person> and Comparable<Person>
You need to take a look at the Comparator interface as well as the Comparable interface.
Your Person should implement comparable in that way that you usually want a person to be sorted. Then you should write some implementations of Comparator.
public classPersonNameComparator implements Comparator<Person> {
public int compare(Person p1, Person p2) {
return p1.name.compareTo(p2.name);
}
}
The importance of using the #Override annotation
It is important to always use the #Override annotation whenever you are trying to override a method of a super class or implement an interface method. The following are a few links regarding why this is a good idea:
Overriding the java equals() method quirk
When do you use Java's #Override annotation and why?
One issue that I see is that TreeMap sorts by key not by value. Your compareTo will not be used in the sorting of the tree since it is the value in the map. Since the key in the map is the id the the items in the tree should be sorted by the id of the person.
How do you know that the map isn't sorted? Can you show us some output that shows that it is not? Are you by any chance changing the ID of the Person after it gets put into the map?
Oh, and what is names compared to personMap? Also, are the ids really contiguous starting from 1? What does this code spit out:
for (Person person : peopleMap.values()) {
System.out.println(person);
}
did you use the #Override method to make sure that you are actually overriding the toString method? It looks like it is still printing out the default toString() (ie the value of the pointer to the object).
see : comparator API.
"The ordering imposed by a Comparator c on a set of elements S is said to be consistent with equals if and only if (compare((Object)e1, (Object)e2)==0) has the same boolean value as e1.equals((Object)e2) for every e1 and e2 in S."
I don't see an equals method in your Person class. The default implementation of equals compares identity. And if you override equals, you must define hashCode two.
And this question : Consistent Equals() results, but inconsistent TreeMap.containsKey() result
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;
public class Person implements Comparable<Person> {
public final String name;
public final int id;
public final Date birthdate;
public Person(int id, String name, Date birthdate) {
this.id = id;
this.name = name;
this.birthdate = birthdate;
}
public static void main(String[] args) {
List<Person> list = new ArrayList<Person>();
for (int i = 10; i > 0; i--) {
list.add(new Person(i, "name" + String.valueOf(i), new Date()));
}
System.out.println(list);
Collections.sort(list);
System.out.println(list);
}
#Override
public boolean equals(Object other) {
if (!(other instanceof Person)) {
return false;
}
return this.id == ((Person)other).id;
}
#Override
public int hashCode() {
return 41 * id;
}
#Override
public String toString() {
return "Person<" + id + ">";
}
#Override
public int compareTo(Person other) {
if (!(other instanceof Person)) {
throw new IllegalArgumentException();
}
return this.id - ((Person)other).id;
}
}
Outputs :
[Person<10>, Person<9>, Person<8>, Person<7>, Person<6>, Person<5>, Person<4>, Person<3>, Person<2>, Person<1>]
[Person<1>, Person<2>, Person<3>, Person<4>, Person<5>, Person<6>, Person<7>, Person<8>, Person<9>, Person<10>]

Categories

Resources