I have two lists containing names. The first list l1
has selected names, and the second list l2
has all the names.
Example:
List<String> l1 = {"en", "cu", "eu"};
List<String> l2 = {"ch", "cu", "en", "eu", "pe"};
All the elements in l1
always exist in l2
.
I want to obtain the output where all the common names are placed at the beginning followed by the remaining names, and I need them to be sorted in the ascending order. Like this:
output -> {cu, en, eu, ch, pe};
What I was trying to do I've shown below, but don't getting the idea that how to place common elements at the starting position (2nd list is already sorted) and place the remaining elements after the common elements
List<String> common = l2.stream().filter(l2::contains).collect(Collectors.toList());
CodePudding user response:
If I understood correctly, you want to sort the elements from the second list l2
by placing the values that are present in the first list l1
at the beginning, and both part should be sorted in the alphabetical order.
You need to define a custom Comparator
for that purpose. Since Java 8 the recommended way to create a Comparator is to use static factory methods like Comparator.comparing()
.
While implementing the Comparator, firstly we need to check if a particular value is present in the first list and order the elements by the result of this check (reminder: natural ordering of boolean
values is false
-> true
). And since contains()
on a list is costful (it does iteration over the list under the hood and therefore runs in O(n)) it would be performance-wise to dump the data from the first list into a HashSet
and perform checks against this Set.
The in order to sort both parts of the list alphabetically, we need can chain the second comparator by applying Comparator.thenComparing()
and providing Comparator.naturalOrder()
as the argument.
Here's how it might be implemented:
List<String> l1 = List.of("en", "cu", "eu");
List<String> l2 = List.of("ch", "cu", "en", "eu", "pe");
// output -> {cu,en,eu,cu,pe};
Set<String> toCheck = new HashSet<>(l1);
Comparator<String> comparator =
Comparator.<String,Boolean>comparing(toCheck::contains).reversed()
.thenComparing(Comparator.naturalOrder());
List<String> sorted = l2.stream()
.sorted(comparator)
.toList(); // for Java 16 or collect(Collectors.toList())
System.out.println(sorted);
Output:
[cu, en, eu, ch, pe]