5

I have a list of data like the one given below:

List<Data> data = new ArrayList<Data>();
data.add(new Data("d1", "option1"));
data.add(new Data("d2", "option1"));
data.add(new Data("d1", "option2"));
data.add(new Data("d3", "option1"));
data.add(new Data("d3", "option2"));
data.add(new Data("d3", "option3"));

The structure looks like this:

class Data {
    private String name;
    private String option;
    private List<String> options = new ArrayList<>();
    public Data(String name, String option) {
        this.name = name;
        this.option = option;
    }

    public void addOption(String option) {
        options.add(option);
    }
}

How to group the items to a new array based on the name with its options,

[
"d1": {
    "name": "d1",
    "options": ["option1", "option2"]
},
"d2": {
    "name": "d2",
    "options": ["option1"]
},
"d3": {
    "name": "d3",
    "options": ["option1", "option2", "option3"]
}
]
3
  • To clarify: Do you want the output as a JSON-String? Or a way to get all option fields in the options field of a new instance of Data? For the latter I would already recommend to change something because it's weird to have both a list of options and a single String option in your class if they both basically mean the same. Commented May 30, 2018 at 6:22
  • 2
    You can't instantiate List; it's an interface. Why does Data have both a single option and a list of options? You never call addOption. Also, you can't group them to an array. Do you mean a Map? Commented May 30, 2018 at 6:26
  • No JSON, just for brevity I have given the object structure like that. Commented May 30, 2018 at 6:52

4 Answers 4

4

You can use a Collectors.toMap collector:

Map<String,Data>
    grouped = data.stream()
                  .collect(Collectors.toMap(Data::getName,
                                            d -> new Data(d.getName(),d.getOption()),
                                            (d1,d2) -> {d1.addOptions(d2.getOptions()); return d1;});

This will require changing the Data constructor to add the passed option to the options List as well as adding an addOptions method that receives a list of options and adds all of them to the options List of the current instance.

Sign up to request clarification or add additional context in comments.

1 Comment

This approach looks convenient for me, I get collection of type "Data" as values from the result map, than of type List<String>.
3

Try this out,

final Map<String, List<String>> optionsByName = dataList.stream().collect(
        Collectors.groupingBy(Data::getName, Collectors.mapping(Data::getOption, Collectors.toList())));

I would suggest you to use this map as a source to create the DTO you need, without cluttering your code to get the exact result you want.

Comments

2

You can use a simple grouping collector on the stream:

Map<String, List<String>> optionMap = data.stream()
            .collect(Collectors.groupingBy(Data::getName, 
                     Collectors.mapping(Data::getOption, Collectors.toList())));

When tested with your test list, the above produces this output:

{d1=[option1, option2], d2=[option1], d3=[option1, option2, option3]}

The above seems like a better, type-safe alternative to your desired map. Additionally, it avoids unnecessary duplication.

Your final map can nonetheless be computed based on the above:

Map<String, Map<String, Object>> m = new HashMap<>();
optionMap.entrySet().forEach(entry -> {
    Map<String, Object> map = new HashMap<>();
    map.put("name", entry.getKey());
    map.put("options", entry.getValue());

    m.put(entry.getKey(), map);
});

The m map above looks like:

{d1={name=d1, options=[option1, option2]}, 
 d2={name=d2, options=[option1]}, 
 d3={name=d3, options=[option1, option2, option3]}}

This is what you need, but it seems that it contains duplicated data, and it's less type-safe than the simple map in the previous result.

Comments

0

public class Test2 {

    static List<Employee> getAllEmployees() {
        List<Employee> employeeList = new ArrayList<Employee>();
        Employee e1= new Employee("sudhansu",46,135000.00,"JAVA");
        Employee e2= new Employee("Himanshu",26,135000.00,"JAVA");
        Employee e3= new Employee("Pabitra",53,135000.00,"ORACLE");
        Employee e4= new Employee("Rajan",36,135000.00,"Hibernate");
        Employee e5= new Employee("Raman",36,135000.00,"JAVA");
        Employee e6= new Employee("Sambhu",26,135000.00,"MYSQL");
        Employee e7= new Employee("Sagar",37,135000.00,"ORACLE");
        Employee e8= new Employee("Ranjeet",26,135000.00,".NET");
        Employee e9= new Employee("Chitra",46,135000.00,".NET");
        Employee e10= new Employee("Minu",28,135000.00,".NET");
        employeeList.add(e1);
        employeeList.add(e2);
        employeeList.add(e3);
        employeeList.add(e4);
        employeeList.add(e5);
        employeeList.add(e6);
        employeeList.add(e7);
        employeeList.add(e8);
        employeeList.add(e9);
        employeeList.add(e10);
        return employeeList;
    }
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        List<Employee> empList= getAllEmployees();
        Map<String, List<String>> map1=empList.stream().collect(Collectors.groupingBy(e->e.getSkills(),LinkedHashMap::new,
                Collectors.mapping(Employee::getName,Collectors.toList())));
        System.out.println("employee map"+map1);
    }

}

2 Comments

same.....almost
Explanation? Notes?

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.