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