Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Convert List stream into single Container

Consider the below WorkExperience class:

public class WorkExperience {
    private int year;
    private List<Skills> skill;

    public WorkExperience(int year, List<Skills> skill) {
        this.year = year;
        this.skill = skill;
    }   
    //getter setter         
}

public class Skills {
    private String skills;

    public Skills(String skills) {
        this.skills = skills;
    }

    @Override
    public String toString() {
        return "Skills [skills=" + skills + "]";
    }
}     

let's say I want to group by my skills by year, this is how we can do groupBy by year:

public static void main(String[] args) {

    List<Skills> skillSet1 = new  ArrayList<>();
    skillSet1.add(new Skills("Skill-1"));
    skillSet1.add(new Skills("Skill-2"));
    skillSet1.add(new Skills("Skill-3"));

    List<Skills> skillSet2 = new  ArrayList<>();
    skillSet2.add(new Skills("Skill-1"));
    skillSet2.add(new Skills("Skill-4"));
    skillSet2.add(new Skills("Skill-2"));


    List<Skills> skillSet3 = new  ArrayList<>();
    skillSet3.add(new Skills("Skill-1"));
    skillSet3.add(new Skills("Skill-9"));
    skillSet3.add(new Skills("Skill-2"));

    List<WorkExperience> workExperienceList = new ArrayList<>();
    workExperienceList.add(new WorkExperience(2017,skillSet1));
    workExperienceList.add(new WorkExperience(2017,skillSet2));
    workExperienceList.add(new WorkExperience(2018,skillSet3));

    Map<Integer, Set<List<Skills>>> collect = workExperienceList.stream().collect(
        Collectors.groupingBy(
            WorkExperience::getYear,
            Collectors.mapping(WorkExperience::getSkill, Collectors.toSet())
        )
    );
}

groupBy is returning: Map<Integer, Set<List<Skills>>>
but what I need is: Map<Integer, Set<Skills>>

How to convert List stream into single Container?

like image 563
Niraj Sonawane Avatar asked Jan 17 '18 18:01

Niraj Sonawane


People also ask

How do you flatten a stream List?

The standard solution is to use the Stream. flatMap() method to flatten a List of Lists. The flatMap() method applies the specified mapping function to each element of the stream and flattens it.

How to convert a stream to a list in Java?

The Collector class is used to collect the elements of the Stream into a collection. This class has the toList () method, which converts the Stream to a List. This example is similar to the previous one except that we used the Collector.toList () method instead of the Collectors.toCollection () method.

How to collect a stream into a LinkedList in Java?

In such simple usecases, Stream.collect () API is best suited along with Collectors.toList (). Stream<String> tokenStream = Stream.of ("A", "B", "C", "D"); Program output. 2. Collecting Stream into LinkedList The given example is only slightly different from the first example. Here, we are collecting the Stream items into a LinkedList.

What are the different types of content in stream (classic)?

Content in Stream (Classic) is divided into five container types: Stream group (Videos in Stream group) (if you didn't migrate from office 365 video, your tenant would not have it) Orphaned container (Videos with no owner) [Not available in Preview] We'll choose the default destination for some types of containers, which admins can override.

What is a stream in Java 8?

A Stream is a collection of objects. A Stream doesn’t store any data, and therefore it is not a data structure. The Stream was added to the Java 8 version, whereas a List is an interface that stores ordered collections. In this tutorial, we will look into converting a Stream to a List.


Video Answer


2 Answers

An alternative to flatMapping using Java 8 features only would be

Map<Integer, Set<Skills>> map = workExperienceList.stream()
    .collect(Collectors.toMap(
        WorkExperience::getYear,
        we -> new HashSet<>(we.getSkill()),
        (s1, s2)-> { s1.addAll(s2); return s1; }));

you may optimize this a bit

Map<Integer, Set<Skills>> map = workExperienceList.stream()
    .collect(Collectors.toMap(
        WorkExperience::getYear,
        we -> new HashSet<>(we.getSkill()),
        (s1, s2) -> {
            if(s1.size() > s2.size()) { s1.addAll(s2); return s1; }
            else { s2.addAll(s1); return s2; }
        }));
like image 94
Holger Avatar answered Sep 19 '22 14:09

Holger


We can use Collectors.flatMapping collector added in Java-9. By using flatMapping, we can flatten the intermediate Lists into a single container. flatMapping can be used in the cases where elements of the original stream are convertible to a stream.

workExperienceList.stream().collect(Collectors.groupingBy(
                              WorkExperience::getYear, 
                              Collectors.flatMapping(workexp -> workexp.getSkill().stream(), 
                                             Collectors.toSet())));

API Note:

The flatMapping() collectors are most useful when used in a multi-level reduction, such as downstream of a groupingBy or partitioningBy.

like image 24
Niraj Sonawane Avatar answered Sep 18 '22 14:09

Niraj Sonawane