Sort a list of Comparables using multiple string fields in a custom order
Sort a list of Comparables using multiple string fields in a custom order
With this class:
public class MyClass implements Comparable<MyClass> {
private String status;
private String name;
private String firstName;
@Override
public int compareTo(MyClass o) {
return 0;
}
}
I'd like to sort a list of MyClass objects with this order:
How can I do this with the Comparable
interface ?
Comparable
stackoverflow.com/questions/369512/… I tried the third answer in this post assuming I'm not using java 8. My filters are not the same, I don't know how to check by "keys"
– whySoSerious
Jun 29 at 9:32
Are these the only available names? I.e.
toto
, titi
, tutu
, tata
? If not, then what's the general rule for sorting? Anyway, here is how you can use the comparator: List<MyClass> list = ...; Collections.sort(list);
– Tamas Rev
Jun 29 at 9:38
toto
titi
tutu
tata
List<MyClass> list = ...; Collections.sort(list);
2 Answers
2
I would do this like so: first define a set of lists which define the order for each field:
private static List<String> statusOrder = Arrays.asList("open", "working", "close");
private static List<String> nameOrder = Arrays.asList("toto", "titi");
private static List<String> firstNameOrder = Arrays.asList("tutu", "tata");
Then use List.indexOf
to get the position of the element in the list, and then simply subtract the results:
List.indexOf
@Override
public int compareTo(MyClass o) {
final int statusComp = statusOrder.indexOf(status) - statusOrder.indexOf(o.status);
if (statusComp != 0) return statusComp;
final int nameComp = nameOrder.indexOf(name) - nameOrder.indexOf(o.name);
if (nameComp != 0) return nameComp;
return firstNameOrder.indexOf(firstName) - firstNameOrder.indexOf(o.firstName);
}
The issue with this approach is that indexOf
will return -1 if the element is not in the list. You would need to define the behaviour in the case where MyClass
contains non-standard values (perhaps it will never happen).
indexOf
MyClass
@DidierL I thought the agreement was sarcastic? I don't see it as an exact duplicate. That question wants to sort multiple string fields alphabetically, this question wants to sort multiple string fields, each with a defined non-alphabetic order. I've tried to improve the question to make it a clearer non-dupe.
– Michael
Jun 29 at 9:53
Ok, let's leave it open then.
– Didier L
Jun 29 at 12:12
I wrote you a class. It has a main method, so you can run it. The main method fills a list with MyClass objects, prints them, sorts them and prints them again:
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
public class MyClass implements Comparable<MyClass> {
private static class STATUS {
public static final String OPEN = "open";
public static final String WORKING = "working";
public static final String CLOSE = "close";
}
private static class NAME {
public static final String TOTO = "toto";
public static final String TITI = "titi";
}
private static class FIRST_NAME {
public static final String TUTU = "tutu";
public static final String TATA = "tata";
}
public MyClass(String status, String name, String firstName) {
this.status = status;
this.name = name;
this.firstName = firstName;
}
private String status;
private String name;
private String firstName;
@Override
public int compareTo(MyClass o) {
if(!equals(this.status, o.status)) {
return getIndex_status(this.status) - getIndex_status(o.status);
} else if(!equals(this.name, o.name))
return getIndex_name(this.name) - getIndex_name(o.name);
return getIndex_firstName(this.firstName) - getIndex_firstName(o.firstName);
}
private int getIndex_status(String status) {
return getIndex(status, new String {STATUS.OPEN, STATUS.WORKING, STATUS.CLOSE});
}
private int getIndex_name(String name) {
return getIndex(name, new String {NAME.TOTO, NAME.TITI});
}
private int getIndex_firstName(String firstName) {
return getIndex(firstName, new String {FIRST_NAME.TUTU, FIRST_NAME.TATA});
}
private int getIndex(String value, String values) {
int index = Arrays.asList(values).indexOf(value);
return index == -1 ? values.length : index;
}
@Override
public String toString() {
return "status: " + this.status + " | name: " + this.name + " | firstName: " + this.firstName;
}
public static void main(String args) {
List<MyClass> myObjects = new ArrayList<>();
myObjects.add(new MyClass(STATUS.WORKING, "aName", "aFirstName"));
myObjects.add(new MyClass(STATUS.OPEN, "aName", "aFirstName"));
myObjects.add(new MyClass(STATUS.CLOSE, "aName", "aFirstName"));
myObjects.add(new MyClass(STATUS.CLOSE, "aName", null));
myObjects.add(new MyClass(STATUS.CLOSE, NAME.TITI, "aFirstName"));
myObjects.add(new MyClass(STATUS.CLOSE, NAME.TOTO, "aFirstName"));
myObjects.add(new MyClass(STATUS.CLOSE, null, "aFirstName"));
myObjects.add(new MyClass(STATUS.CLOSE, "aName", FIRST_NAME.TATA));
myObjects.add(new MyClass(null, "aName", FIRST_NAME.TATA));
myObjects.add(new MyClass(STATUS.CLOSE, "aName", FIRST_NAME.TUTU));
System.out.println("before sorting:");
print(myObjects);
Collections.sort(myObjects);
System.out.println("after sorting:");
print(myObjects);
}
private static void print(List<MyClass> myObjects) {
for(MyClass myObject : myObjects) {
System.out.println(myObject);
}
}
private static boolean equals(String s1, String s2) {
if(s1 == null)
return s2 == null;
return s1.equals(s2);
}
}
why the downvote?
– Tom
12 hours ago
By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.
Well, what have you tried so far?
– Laurens
Jun 29 at 9:29