Home > Mobile >  How to Sort a Nested List of strings
How to Sort a Nested List of strings

Time:05-21

I want to sort the list by values in the list. I want to do multisorting based on few parameters in the list. Providing sample example how data looks like.

Note: I don't have feasibility to convert List<List<String>> into a list of objects.

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

I want to do multi sorting based on name, age and city.

It's just sample data. List of lists is dynamic. Sorting parameters will also change sometimes.

I want to do sorting on a list of lists of strings only.

Expected Output: List<List<String>> sortedData

CodePudding user response:

Solution by Maintaining your Structure

If you can't really create a class wrapping the data in your nested List (for whatever reason), you could use the collection stream and define the sorted operation's logic as follows:

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

Link to test the code above:

https://ideone.com/RhW1VI

Alternative Solution

However, as it has been pointed out in the comments, a better approach would be to create a custom class representing your data in the nested List. Perhaps a simple record if you're using Java 14 or later with a factory method to retrieve an instance of your class from a nested List.

Then, with a stream you could map each nested list to your custom class and sort it with a Comparator.

Here is a snippet of the implementation:

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

Mapping record

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

Here there is also a link with both implementations:

https://ideone.com/UK9trV

CodePudding user response:

In order to impose the order of lists inside a nested list need to define a Comparator.

As you've said that contents of the list will can't be predicted in advance, I assume that nested lists might be of arbitrary size and their sizes might not be equal.

A comparator that can handle such case might be written like that:

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

In order to sort the list, you can apply method sort() on it (available with Java 8 ) which expects a comparator:

data.sort(listComparator);

And you can make a defensive copy of the list before applying sort(), if its initial order might be useful for you:

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

data.sort(listComparator);
  • Related