stackattack
stackattack

Reputation: 354

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 second value in subarray, if there is two a like then it should sort by third value and if it finds two a like from there then it should sort them by first element. So final result should look like that:

[["e", "one", 1], ["b", "one", 2], ["a", "one", 3], ["c", "one", 4], ["f", "two", 1], ["d", "two", 2]]

Can someone show me some good way to do it?

Thanks!

Upvotes: 3

Views: 1941

Answers (4)

Pshemo
Pshemo

Reputation: 124285

["a", "one", 3] should be instance of your class like

class Item{
    private String val1;
    private String val2;
    private int val3;
    //getters and setters
}

This way your list would be List<Item>. Now you can simply use Collections.sort(list, yourComparator) or if you are using Java 8 list.sort(yourComparator).

As yourComparator you can pass instance of class implementing Comparator interface, for instance in a 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 probably more readable and possibly easier approach would be creating separate comparators for each field and combining them. If you are using Java 8 your code can look like:

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));

Upvotes: 3

Alex Salauyou
Alex Salauyou

Reputation: 14348

Supposing than "one" is less than "two" (since "o" < "t"), and I do not see any other "string numerics"* here, a simple comparator can be written:

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 using this comparator:

Collections.sort(list, c);

*For other "string numerics" such as "three", "four" and so on, if you need them to be compared by meaning, not lexographically, you would need to define special mapping, which would convert its "meaning" to Integer number. But this is out of scope of this question; post a new one to let not-so-busy programmers practice in dummy speed coding.

Upvotes: 2

pathfinderelite
pathfinderelite

Reputation: 3147

As duffymo suggests, use a list of Objects. A simple struct will 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 the struct implements Comparable, you can just sort: No need for a Comparator.

Collections.sort(list);

Upvotes: 0

duffymo
duffymo

Reputation: 309028

A good way to do this? Not the way you're thinking. A List of Lists is too primitive; a List of custom objects would be better.

Write custom Comparators for the cases you want to run.

Upvotes: 2

Related Questions