Группировка по объекту - потоки Java - PullRequest
0 голосов
/ 30 мая 2018

У меня есть список данных, подобный приведенному ниже:

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"));

Структура выглядит следующим образом:

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);
    }
}

Как сгруппировать элементы в новый массив на основеимя с его параметрами,

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

Ответы [ 3 ]

0 голосов
/ 30 мая 2018

Попробуйте,

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

Я бы посоветовал вам использовать этот map в качестве источника для создания нужного вам DTO, не загромождая код для получения желаемого результата.

0 голосов
/ 30 мая 2018

Вы можете использовать простой групповой сборщик в потоке:

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

При тестировании с вашим тестовым списком приведенный выше вывод выдаст:

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

Выше похоже наЛучшая, безопасная альтернатива вашей карте.Кроме того, он позволяет избежать ненужного дублирования.

Ваша окончательная карта, тем не менее, может быть рассчитана на основе вышеизложенного:

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);
});

Карта m, приведенная выше, выглядит следующим образом:

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

Это то, что вам нужно, но, похоже, он содержит дублированные данные и менее безопасен для типов, чем простая карта в предыдущем результате.

0 голосов
/ 30 мая 2018

Вы можете использовать Collectors.toMap сборщик:

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;});

Для этого потребуется изменить конструктор Data, чтобы добавить переданный параметр в параметры List, а также добавить метод addOptionsкоторый получает список опций и добавляет их все к опциям List текущего экземпляра.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...