0

Considering I have a list of objects List<Emp> where Emp has 3 properties name, id, and age. What is the fastest way to get 3 lists like List<String> names, List<String> ids, and List<Integer> ages.

The simplest I could think of is to iterate over the entire list and keep adding to these 3 lists. But, I was wondering if there is an easier way to do it with Java 8 streams?

Thanks in advance.

2
  • 2
    I believe iterating over the entire list would be the quickest option... anything with streams I think would require 3 separate streams, thus 3 iterations compared to one Commented Apr 10, 2020 at 15:31
  • 2
    The simplest I could think of is to iterate over the entire list and keep adding to these 3 lists. - This is the simplest way. Do not try to make it unnecessarily complex using Stream. Commented Apr 10, 2020 at 15:32

2 Answers 2

1

It's a very interesting question, however, there is no dedicated collector to handle such use case.

All you can is to use 3 iterations (Streams) respectively:

List<String> names = employees.stream().map(Emp::name).collect(Collectors.toList());
List<Integer> ids = employees.stream().map(Emp::id).collect(Collectors.toList());
List<Integer> ages = employees.stream().map(Emp::age).collect(Collectors.toList());

Edit - write the own collector: you can use the overloaded method Stream::collect(Supplier, BiConsumer, BiConsumer) to implement your own collector doing what you need:

Map<String, List<Object>> newMap = employees.stream().collect(
    HashMap::new,                                               // Supplier of the Map
    (map, emp) -> {                                             // BiConsumer accumulator
        map.compute("names", remappingFunction(emp.getName())); 
        map.compute("ages", remappingFunction(emp.getAge()));
        map.compute("ids", remappingFunction(emp.getId()));
    },
    (map1, map2) -> {}                                          // BiConsumer combiner
);

Practically, all it does is extracting the wanted value (name, age...) and adding it to the List under the specific key "names", "ages" etc. using the method Map::compute that allows to compute a new value based on the existing (null by default if the key has not been used).

The remappingFunction that actually creates a new List or adds a value looks like:

private static BiFunction<String, List<Object>, List<Object>> remappingFunction(Object object) {
    return (key, list) -> {
        if (list == null)
            list = new ArrayList<>();
        list.add(object);
        return list;
    };
}
Sign up to request clarification or add additional context in comments.

Comments

0

Java 8 Stream has some API to split the list into partition, such as: 1. Collectros.partitioningBy(..) - which create two partitions based on some Predicate and return Map<Boolean, List<>> with values; 2. Collectors.groupingBy() - which allows to group stream by some key and return resulting Map.

But, this is not really your case, since you want to put all properties of the Emp object to different Lists. I'm not sure that this can be achieved with such API, maybe with some dirty workarounds.

So, yes, the cleanest way will be to iterate through the Emp list and out all properties to the three Lists manually, as you have proposed.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.