Piotr Rogowski
Piotr Rogowski

Reputation: 3890

Stream Collection to other structure

I try convert list objects of Dictionary to object with contains list.

public class Dictionary {
    private String dictCode;
    private String dictName;
    private String dictDescription;
    private String dictElemCode;
    private String dictElemName;
    private String dictElemDescription;

}

//parent
public class DictDTO {

    private String code;
    private String value;
    private String description;
    private List<DictElemDTO> listDictElemDTO;
}

//children
public class DictElemDTO {

    private String code;
    private String value;
    private String description;
}

Example data for Dictionary class:

Dictionary d1 = new Dictionary("a1", "dict1", "desc1", "elem_code_1", "elem_code_name", "elem_code_desc");
Dictionary d2 = new Dictionary("a1", "dict1", "desc1", "elem_code_2", "elem_code_name2", "elem_code_desc2");
Dictionary d3 = new Dictionary("a2", "dict2", "desc2", "elem_code_3", "elem_code_name3", "elem_code_desc3");

And the result should by like this:

a1
------ elem_code_1
------ elem_code_2
a2
------ elem_code_3

My solution for stream works but it's slow because I use stream of list more than once.

public static void main(String[] args) {
        Dictionary d1 = new Dictionary("a1", "dict1", "desc1", "elem_code_1", "elem_code_name", "elem_code_desc");
        Dictionary d2 = new Dictionary("a1", "dict1", "desc1", "elem_code_2", "elem_code_name2", "elem_code_desc2");
        Dictionary d3 = new Dictionary("a2", "dict2", "desc2", "elem_code_3", "elem_code_name3", "elem_code_desc3");

        List<Dictionary> list = ImmutableList.of(d1, d2, d3);


        List<DictDTO> newList = list.stream().filter(distinctByKey(Dictionary::getDictCode)).map(t -> {
            DictDTO dto = new DictDTO();
            dto.setCode(t.getDictCode());
            dto.setValue(t.getDictName());
            dto.setDescription(t.getDictDescription());
            dto.setListDictElemDTO(
                                   list.stream().filter(e -> e.getDictCode().equals(t.getDictCode())).map(w -> {
                                       DictElemDTO elemDto = new DictElemDTO();
                                       elemDto.setCode(w.getDictElemCode());
                                       elemDto.setValue(w.getDictElemName());
                                       elemDto.setDescription(w.getDictElemDescription());
                                       return elemDto;
                                   }).collect(Collectors.toList())
                            );
            return dto;
        }).collect(Collectors.toList());

        for (DictDTO dto : newList) {
            System.err.println(dto.getCode());
            for (DictElemDTO dtoE : dto.getListDictElemDTO()) {
                System.err.println("------ " + dtoE.getCode());
            }
        }

    }

static <T> Predicate<T> distinctByKey(Function<? super T, ?> keyExtractor) {
        Map<Object, Boolean> seen = new ConcurrentHashMap<>();
        return t -> seen.putIfAbsent(keyExtractor.apply(t), Boolean.TRUE) == null;
    }

What is better approach for this problem using stream in Java 8?

Upvotes: 0

Views: 121

Answers (1)

Eran
Eran

Reputation: 394126

This looks like a job for Collectors.groupingBy:

Map<String,List<DictElemDTO>>
    map = Stream.of(d1,d2,d3)
                .collect(Collectors.groupingBy(Dictionary::getDictCode,
                                               Collectors.mapping(d-> new DictElemDTO (d.getDictElemCode(),d.getDictElemName(),d.getDictElemDescription()), 
                                                                  Collectors.toList())));

This will give you a mapping of dictionary codes to the corresponding list of DictElemDTOs.

It requires a bit more work to create the DictDTO objects.

Upvotes: 2

Related Questions