I am trying to arrive at a solution for a problem related to sorting.
The input is a list of values where each value in list is a list containing two String
values {name,id}
An Example input list resembles
{{name99,id1},{name2,id2},{name36,id3}}
My requirement is to sort these based on both input sort condition and sort order. If sort condition is "name", with asc as input order criteria, then my output list should be:
{{name2,id2},{name36,id3},{name99,id1}}
If sort condition is "id", with desc as input order criteria, then my output list should be:
{{name36,id3},{name2,id2},{name99,id1}}
CodePudding user response:
The following shows the comparators used for sorting, and then a generic method in order to use the comparator as well as whether the order should be in desc or asc.
public static void main(String[] args) {
List<String> item1 = Arrays.asList("name99","id1");
List<String> item2 = Arrays.asList("name2","id2");
List<String> item3 = Arrays.asList("name36","id3");
List<List<String>> listOfLists = Arrays.asList(item1, item2, item3);
Comparator<List<String>> nameComparator = (l1, l2) -> l1.get(0).compareTo(l2.get(0));
Comparator<List<String>> idComparator = (l1, l2) -> l1.get(1).compareTo(l2.get(1));
//sort by name in asc
listOfLists.sort(nameComparator);
System.out.println(listOfLists);
//instead of making a new comparator with l2 compared to l1, just call comparator.reversed()
listOfLists.sort(nameComparator.reversed());
System.out.println(listOfLists);
//testing out generic method to pass list of lists, sort comparator and the ordering of the sort.
sortListByComparatorAndOrder(listOfLists, idComparator, "DESC");
System.out.println(listOfLists);
}
//generic method to sort a list
public static <T> void sortListByComparatorAndOrder(List<T> listToSort, Comparator<T> sorter, String order) {
if (order.equals("ASC")) {
listToSort.sort(sorter);
}else if (order.equals("DESC")) {
listToSort.sort(sorter.reversed());
}
}
output:
[[name2, id2], [name36, id3], [name99, id1]]
[[name99, id1], [name36, id3], [name2, id2]]
[[name36, id3], [name2, id2], [name99, id1]]
Special note: I suspect that this logic might not be a good idea considering that there are integers in the name. while name2 comes before name36, name2 will NOT come before name16, so I think this might not be the best logic for a comparator.
IF the id are string representations of numbers ie "9" "10" and not a mix of alphabet and numbers "id9" "id10", you could instead parse the numbers from the string in order to avoid the issue mentioned above in the note. ie:
Comparator<List<String>> idComparator = (l1, l2) -> {
Integer val1 = Integer.parseInt(l1.get(1));
Integer val2 = Integer.parseInt(l2.get(1));
return val1.compareTo(val2);
};
CodePudding user response:
You can use apache's org.apache.commons.lang3.tuple.Pair to model it. This should cover all 4 cases:
List<Pair<String, String>> list = new ArrayList<>();
list.add(new MutablePair<>("name99", "id1"));
list.add(new MutablePair<>("name2", "id2"));
list.add(new MutablePair<>("name36", "id3"));
list.sort(Comparator.comparing(Pair::getLeft));// name, asc
list.sort(Comparator.comparing(Pair::getLeft, Collections.reverseOrder()));// name, desc
list.sort(Comparator.comparing(Pair::getRight)); // id, asc
list.sort(Comparator.comparing(Pair::getRight, Collections.reverseOrder())); // id, desc