按子列表中的项目对Java列表进行排序

3

我有一个列表:

List<List<Item>> = [["a", "one", 3], ["b", "one", 2], ["c", "one", 4], ["d", "two", 2],["e", "one", 1], ["f", "two", 1]]

我希望按子数组中的第二个值对其进行排序,如果有两个相同的a,则应该按第三个值进行排序,如果从那里找到两个相同的a,则应该按第一个元素对它们进行排序。因此,最终结果应该是这样的:

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

有人可以向我展示一些好的方法来做到这一点吗?

谢谢!


比较器的答案是正确的,但我警告不要假定你拥有的任何列表都会有任何元素,更不用说两个或更多了。除非这是一项人为的家庭作业,否则最好创建一个具有字段的类,然后编写自定义比较器。此外,请注意您正在对其进行排序的字段的数据类型......字符串的默认比较将是字符串比较,这与将“one”转换为数字1并进行比较非常不同。 - Gus
4个回答

3

["a", "one", 3] 应该是你的类的实例,例如

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

这样,你的列表将是List<Item>。现在你可以简单地使用Collections.sort(list, yourComparator)或者如果你使用Java 8,可以使用list.sort(yourComparator)
作为yourComparator,你可以传递实现Comparator接口的类的实例,例如:
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());
    }
};

但更易读且可能更容易的方法将是为每个字段创建单独的比较器并将它们组合在一起。如果您正在使用Java 8,则您的代码可以如下:

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

["a", "one", 3] 明显是一个 List,因为 OP 将整个集合声明为 List<List<Item>> - Alex Salauyou
@SashaSalauyou 我知道,但由于它包含不同类型的数据,最好将其作为单独的类而不是 List<Objects> 或没有泛型类型的列表。 - Pshemo
肯定的是))) 我们在这里只是为了快速编码。 - Alex Salauyou

2
假设"one"小于"two"(因为"o" < "t"),并且我没有看到其他的“字符串数字”,那么可以编写一个简单的比较器:
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));
    }
}

然后使用这个比较器进行排序:

Collections.sort(list, c);

*对于其他的“字符串数字”,比如“三”、“四”等,如果你需要按照意义而不是字典序进行比较,你需要定义特殊映射,将它们的“意义”转换为整数。但这超出了本问题的范围;请发布一个新问题,让不那么忙碌的程序员练习虚拟速度编程。


2

如何实现这个目标?不是你想的那样。列表嵌套列表的方式太过原始,使用自定义对象的列表会更好。

编写针对所需情况的自定义比较器。


0
正如duffymo建议的那样,使用对象列表。一个简单的结构体就可以了:
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;

由于结构体实现了Comparable接口,您可以直接排序:无需使用Comparator。

Collections.sort(list);

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接