Java 8 группировка по списку карт - PullRequest
0 голосов
/ 30 марта 2020

У меня есть список карт, для которых я хочу сгруппировать их по имени

List<Map> allObjs = new ArrayList<Map>();
Map<String, Object> src = new HashMap();
src.put("name", "asset1");
src.put("description", "desc1" );
src.put("definition", "def1" );

Map<String, Object> src2 = new HashMap();
src2.put("name", "asset1");
src2.put("description", "desc2" );
src2.put("definition", "def2" );
allObjs.add(src);
allObjs.add(src2);

Я попытался сгруппировать их по

Map<Object, List<Map>> result = allObjs.stream().collect(Collectors.groupingBy(p -> p.get("name")));

Что я хочу, это

{
 name=asset1,
 description=["desc1","desc2"],
 definition=["def1","def2"]
}

Я хочу, чтобы все остальные ключи были сгруппированы в списке. Но я получил

{asset1=[
            {name=asset1, description=desc1, definition=def2},
            {name=asset1, description=desc2, definition=def2}
        ]
}

Как мне сгруппировать все остальные ключи, кроме имени, в список, как ожидалось выше?

Ответы [ 2 ]

2 голосов
/ 30 марта 2020

Вы можете использовать groupBy с mapping, чтобы получить желаемый результат, только значения будут только одного типа,

Map<String, Set<String>> collect1 = allObjs.stream()
                .flatMap(m -> m.entrySet().stream())
                .collect(groupingBy(Map.Entry::getKey, mapping(Map.Entry::getValue, toSet())));

Результат:

{
 name=[asset1],
 description=[desc1,desc2],
 definition=[def1,def2]
}
0 голосов
/ 30 марта 2020

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

Учитывая

List<Map<String, String>> allObjs = new ArrayList<>();
Map<String, String> src = new HashMap();
src.put("name", "asset1");
src.put("description", "desc1" );
src.put("definition", "def1" );

Map<String, String> src2 = new HashMap();
src2.put("name", "asset1");
src2.put("description", "desc2" );
src2.put("definition", "def2" );
allObjs.add(src);
allObjs.add(src2);

Один из способов сделать это - это. Создайте два класса, представляющих существующую структуру и конечную структуру вывода

@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
@ToString
public class SomeClass {
    private String name;
    private String description;
    private String definition;
}

@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
@ToString
public class NewClass {
    private String name;
    private List<String> description;
    private List<String> definition;
}

Тогда этот код должен получить желаемый результат вывода

final List<NewClass> collect = allObjs.stream()
        .map(entry -> new SomeClass(entry.get("name"), entry.get("description"), entry.get("definition")))
        .collect(Collectors.toList())
        .stream()
        .collect(Collectors.groupingBy(SomeClass::getName))
        .entrySet()
        .stream()
        .map(entry -> {
            final List<String> descriptions = entry.getValue().stream().map(SomeClass::getDescription).collect(Collectors.toList());
            final List<String> definitions = entry.getValue().stream().map(SomeClass::getDefinition).collect(Collectors.toList());
            return new NewClass(entry.getKey(), descriptions, definitions);
        }).collect(Collectors.toList());

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

...