Как сгруппировать родительские дочерние объекты, используя Java 8 - PullRequest
0 голосов
/ 03 октября 2018

Я пытаюсь сгруппировать некоторые объекты, помещая дочерние элементы в родительский объект ..

@Entity 
public class JournalEntry {
    Integer id;
    String message;
    Integer parentId;        
}

Объект передачи данных будет выглядеть следующим образом ...

public class JournalDTO {
    public JournalDTO (Integer id, String message, List<JournalDTO> childEntries) {
        this.id = id;
        this.message = message;
        this.childEntries = childEntries;
    }
    Integer id;
    String message;
    List<JournalDTO> childEntries;
}

Так что я надеюсьв итоге получается список, у которого нет родительского идентификатора, то есть верхнего уровня, и тогда у них будет группа дочерних сущностей, а внутри этих дочерних сущностей они также могут иметь дочерние сущности.Есть ли способ сделать это.Моя идея состояла в том, чтобы сначала получить все записи верхнего уровня следующим образом.

List<JournalEntry> journalEntries = service.fetchJournalEntries();
List<JournalEntry> topLevel = journalEntries.stream().filter(e -> null==e.getParentId()).collect(toList());
journalEntries.removeAll(topLevel);
List<JournalDTO> journalDTOs = topLevel.stream()
                            .map(tl -> new JournalDTO(tl.getId(), tl.getMessage(), new ArrayList<JournalDTO>()))
                            .collect(toList());

, затем я сгруппировал оставшиеся записи по родительскому идентификатору.

Map<Integer, List<JournalEntry>> childMap = journalEntries.stream().collect(groupingBy(Integer::getParentId));

Затем я могу выполнить итерациюэту карту и добавьте childEntities к родительской сущности, но это даст мне только второй уровень, и тогда я должен убедиться, что нет дочерних элементов и т. д. ... Есть ли лучший способ сделать это?

1 Ответ

0 голосов
/ 03 октября 2018

Какая интересная проблема.Сначала я определил метод для простоты:

private static JournalDTO toDTO(JournalEntry entry) {
    return new JournalDTO(entry.getId(), entry.getMessage(), new ArrayList<>());
}

Чем я определил несколько небольших вычислительных Map (s), которые помогут мне быстро искать:

    Map<Integer, JournalEntry> identity = entries.stream()
            .collect(Collectors.toMap(JournalEntry::getId, Function.identity()));

    Map<Integer, Set<Integer>> map = entries.stream()
            .collect(Collectors.groupingBy(
                    x -> x.getParentId() == null ? -1 : x.getParentId(),
                    Collectors.mapping(JournalEntry::getId, Collectors.toSet())));

Первыйдолжно быть очевидно, он содержит идентификатор в паре с JournalEntry.

Второй содержит parentId s для набора идентификаторов.В основном:

-1 == 1 // -1 meaning it has no parents
 1 == 2 // 1 has a child with id 2
 2 == 3, 4 // 2 has two children with id 3 and 4
 4 == 5, 6 // ... 

Если подумать - вот как, например, я нахожу целую «семью» (дайте мне знать, если здесь требуется дополнительная информация).

Остальноепростой код с рекурсивным методом:

// get those that have no parents first
Set<Integer> ids = map.get(-1);

// this is the ultimate result 
List<JournalDTO> all = new ArrayList<>();

// for each entity with no parents, start searching in the map
ids.forEach(x -> {
     JournalDTO parentDTO = toDTO(identity.get(x));
     recursive(x, map, identity, parentDTO);
     all.add(parentDTO);
}); 

И, конечно, самая важная часть:

private static void recursive(
        Integer parentId,
        Map<Integer, Set<Integer>> map,
        Map<Integer, JournalEntry> identity,
        JournalDTO journalDTO) {

    Set<Integer> childrenIds = map.get(parentId);

    if (childrenIds != null && !childrenIds.isEmpty()) {
        childrenIds.forEach(x -> {
            JournalDTO childDTO = toDTO(identity.get(x));
            journalDTO.getChildEntries().add(childDTO);
            recursive(x, map, identity, childDTO);
        });
    }
}

Я проверил это для довольно простого случая (тот, который с ==) и, кажется, работает нормально для меня.

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