Sorting java list by items in sublist
I have a list:
List<List<Item>> = [["a", "one", 3], ["b", "one", 2], ["c", "one", 4], ["d", "two", 2],["e", "one", 1], ["f", "two", 1]]
And I would like to sort it by the second value in the subarray, if there are two types, then it should sort by the third value, and if it finds two types from there, then it should sort them by the first element. So the end result should look like this:
[["e", "one", 1], ["b", "one", 2], ["a", "one", 3], ["c", "one", 4], ["f", "two", 1], ["d", "two", 2]]
Can anyone show me a good way to do this?
Thank!
source to share
["a", "one", 3]
should be an instance of your class like
class Item{
private String val1;
private String val2;
private int val3;
//getters and setters
}
So your list will be List<Item>
. Now you can just use Collections.sort(list, yourComparator)
or use Java 8 list.sort(yourComparator)
.
As yourComparator
you can pass an instance of a class that implements the interface Comparator
, for example, in the way
Comparator<Item> yourComparator = new Comparator<Item>() {
@Override
public int compare(Item o1, Item o2) {
//comapre val2
int result = o1.getVal2().compareTo(o2.getVal2());
if (result != 0) return result;
//if we are here val2 in both objects ware equal (result was 0)
result = Integer.compare(o1.getVal3(), o2.getVal3());
if (result != 0) return result;
return o1.getVal1().compareTo(o2.getVal1());
}
};
But a probably more readable and arguably simpler approach is to create separate comparators for each field and combine them. If you are using Java 8 your code might look like this:
Comparator<Item> val1Comparator = Comparator.comparing(Item::getVal1);
Comparator<Item> val2Comparator = Comparator.comparing(Item::getVal2);
Comparator<Item> val3Comparator = Comparator.comparingInt(Item::getVal3);
list.sort(val2Comparator
.thenComparing(val3Comparator)
.thenComparing(val1Comparator));
source to share
Assuming "one"
less "two"
(since "o" < "t"
) and I don't see any other "string numbers" * here, one can simply write a simple comparator:
Comparator<List<Item>> c = new Comparator<List<Item>>() {
int[] order = new int[]{1, 2, 0}; // order to compare: 2nd, then 3rd, finally 1st
@Override
public int compare(List<Item> l1, List<Item> l2) {
for (int i = 0; i < order.length - 1; i++) {
int result = l1.get(i).compareTo(l2.get(i));
if (result != 0) // means that i-th elements are not the same
return result;
}
return l1.get(order.length - 1).compareTo(l2.get(order.length - 1));
}
}
Then sort with this comparator:
Collections.sort(list, c);
* For other "string numbers" such as "three", "four", etc., if you need to compare them meaningfully and not lexically, you will need to define a special collation that converts its "value" "to Integer
But that is beyond the scope of this question; submit a new one so that programmers not busy so busy practice coding at dummy speed.
source to share
As duffymo suggests, use a list of objects. A simple structure would do:
class Triple implements Comparable<Triple> {
Item first;
Item second;
Item third;
int compareTo(Triple other) {
int second = compare(this.second, other.second);
if (second == 0) {
int third = compare(this.third, other.third);
if (third == 0) {
return compare(this.first, other.first);
}
return third;
}
return second;
}
static int compare(Item lhs, Item rhs) {
/* Do your compare here! */
}
}
List<Triple> list;
Since struct implements Comparable, you can just sort: no need for a comparator.
Collections.sort(list);
source to share