Какая интересная проблема.Сначала я определил метод для простоты:
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);
});
}
}
Я проверил это для довольно простого случая (тот, который с ==
) и, кажется, работает нормально для меня.