Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java collect to list but specify pre-defined first two elements order

I have a List<Person> objects. From it I want to get a list of all id's, and I always want the id "abc" and "bob" to come as the 0th and 1st index of the list if available. Is there a way to do this with java streams?

class Person {
   private String id;
}

List<Person> allPeople = ...
List<String> allIds = allPeople.stream().map(Person::id).collect(Collectors.toList());

My approach is:

Set<String> allIds = allPeople.stream().map(Person::id).collect(Collectors.Set());
List<String> orderedIds = new ArrayList<>();
if(allIds.contains("abc")) {
   orderedIds.add("abc");
}
if(allIds.contains("bob")) {
   orderedIds.add("bob");
}
//Iterate through the set and all add all entries which are not bob and abc in the list.
like image 689
user1692342 Avatar asked Mar 04 '23 22:03

user1692342


2 Answers

It seems like you need more of a PriorityQueue rather than a List here, so may be something like this:

PriorityQueue<String> pq = list.stream()
            .map(Person::getId)
            .distinct()
            .collect(Collectors.toCollection(() -> new PriorityQueue<>(
                    Comparator.comparing(x -> !"abc".equals(x))
                            .thenComparing(x -> !"bob".equals(x)))));

If you still need a List though, just drain that pq into one:

List<String> result = new ArrayList<>();
while (!pq.isEmpty()) {
   result.add(pq.poll());
}
like image 177
Eugene Avatar answered Apr 28 '23 18:04

Eugene


I assume that each id occurs only once in the list. With this I would choose a simple straightforward solution:

List<Person> allPeople = ...;
List<String> allIds = allPeople.stream().map(Person::id).collect(toCollection(ArrayList::new));
boolean foundBob = allIds.remove("bob");
if (foundBob) allIds.add(0, "bob");
boolean foundAbc = allIds.remove("abc");
if (foundAbc) allIds.add(0, "abc");

Note that "bob" and "abc" are moved to the head of the list in reverse order. So "abc" is first in the end.

You can make a small utility method for moving an element:

static void moveToHead(List<String> list, String elem) {
  boolean found = list.remove(elem);
  if (found) list.add(0, elem);
}

With this your code is even simpler and easier to understand:

List<Person> allPeople = ...;
List<String> allIds = allPeople.stream().map(Person::id).collect(toCollection(ArrayList::new));
moveToHead(allIds, "bob");
moveToHead(allIds, "abc");
like image 34
Donat Avatar answered Apr 28 '23 18:04

Donat