如何对字符串的嵌套列表进行排序

How to Sort a Nested List of strings

提问人:Satish Jajimoggala 提问时间:5/20/2022 最后编辑:Alexander IvanchenkoSatish Jajimoggala 更新时间:5/20/2022 访问量:719

问:

我想按列表中的值对列表进行排序。我想根据列表中的几个参数进行多重排序。提供数据外观的示例示例。

注意:我无法将 List<List<String>> 转换为对象列表。

List<List<String>> data = new ArrayList<>();
List<String> list1 = new ArrayList<>();
List<String> list2 = new ArrayList<>();
List<String> list3 = new ArrayList<>();

list1.add("Siva"); 
list1.add("20");
list1.add("Hyd");
list1.add("TA");
list1.add("India");  

list2.add("Suresh");    
list2.add("22"); 
list2.add("Banglore");
list2.add("KA");  
list2.add("India");

list3.add("Ramesh"); 
list3.add("24");
list3.add("Chennai"); 
list3.add("TN");
list3.add("India");

data.add(list1);
data.add(list2);
data.add(list2);

我想根据 和 做多排序。nameagecity

这只是示例数据。列表列表是动态的。排序参数有时也会更改。

我只想对字符串列表列表进行排序。

预期输出:List<List<String>> sortedData

Java 列表 排序嵌 套列表 比较器

评论

1赞 XtremeBaumer 5/20/2022
I don't have feasibility to convert data in to list of object->是的,你有。此外,您还需要定义预期的输出。其他方面,没有目标。最后,你需要付出一些努力。
0赞 Satish Jajimoggala 5/20/2022
我想根据姓名、年龄、城市进行多重排序。输出也应仅是字符串列表的列表。内部列表顺序应根据多重排序进行更改
0赞 Ashish Patil 5/20/2022
@SatishJajimoggala,好吧,你只是进入了.如果要根据 排序,则需要创建自定义 POJO & 然后排序。StringListname,age,city
1赞 XtremeBaumer 5/20/2022
按字符串对年龄进行排序将无法按预期工作。使用字符串时,小于"100""20"
0赞 Satish Jajimoggala 5/20/2022
Yaa我能理解..无论我提供什么,它只是样本数据..字符串数据动态列表的列表。排序参数有时也会发生变化

答:

0赞 dani-vta 5/20/2022 #1

通过维护结构来解决问题

如果无法真正创建一个将数据包装在嵌套中的类(无论出于何种原因),则可以使用集合流并定义操作的逻辑,如下所示:Listsorted

List<List<String>> listRes = data.stream()
        .sorted((x, y) -> {
            int res = x.get(0).compareTo(y.get(0));  //Comparing by name
            if (res != 0) return res;
            res = Integer.valueOf(x.get(1)).compareTo(Integer.valueOf(y.get(1))); //Comparing by age (numeric value)
            if (res != 0) return res;
            return x.get(2).compareTo(y.get(2));  //Comapring by city
        })
        .collect(Collectors.toList());

用于测试上述代码的链接:

https://ideone.com/RhW1VI

替代解决方案

但是,正如注释中指出的那样,更好的方法是创建一个自定义类,以表示嵌套 .如果您将 Java 14 或更高版本与工厂方法结合使用,则可能是一个简单的记录,以便从嵌套的 .ListList

然后,使用流,您可以将每个嵌套列表映射到自定义类,并使用 .Comparator

下面是实现的片段:

public static void main(String[] args) {
        List<List<String>> data = /* ... your initialization ... */

        List<MyClass> listSorted = data.stream()
                .map(list -> MyClass.createMyClass(list))
                .sorted(Comparator.comparing(MyClass::getName).thenComparing(MyClass::getAge).thenComparing(MyClass::getCity))
                .collect(Collectors.toList());

        System.out.println(listSorted);
}

映射记录

record MyClass(String name, int age, String city, String code, String country) {

    public static MyClass createMyClass(List<String> list) {
        if (list == null || list.size() < 5) {
            return null;
        }

        MyClass mc = new MyClass();
        mc.name = list.get(0);
        mc.age = Integer.valueOf(list.get(1));
        mc.city = list.get(2);
        mc.code = list.get(3);
        mc.country = list.get(4);

        return mc;
    }
}

这里还有一个与两个实现的链接:

https://ideone.com/UK9trV

评论

0赞 Satish Jajimoggala 5/20/2022
在我的情况下,创建自定义类将不起作用
0赞 dani-vta 5/20/2022
@SatishJajimoggala看看第一个解决方案和我发布的链接。还有一个解决方案是按照需要维护嵌套列表
0赞 Alexander Ivanchenko 5/20/2022 #2

为了在嵌套列表中强加列表的顺序,需要定义一个比较器

正如您所说,无法提前预测列表的内容,我假设嵌套列表可能具有任意大小,并且它们的大小可能不相等。

可以处理这种情况的比较器可以这样写:

Comparator<List<String>> listComparator = new Comparator<>() {
    @Override
    public int compare(List<String> o1, List<String> o2) {
        int limit = Math.min(o1.size(), o2.size());
        for (int i = 0; i < limit; i++) {
            int localResult = o1.get(i).compareTo(o2.get(i));
                    
            if (localResult != 0) 
                return localResult;
        }
        return o1.size() - o2.size();
    }
};

为了对列表进行排序,您可以在其上应用方法(Java 8+ 可用),该方法需要比较器:sort()

data.sort(listComparator);

您可以在申请之前制作列表的防御性副本,如果它的初始顺序可能对您有用:sort()

List<List<String>> initialOrder = new ArrayList<>(data);

data.sort(listComparator);