public static <T, R> List<T> listToTree(List<T> target, Function<T, R> getId, Function<T, R> getParentId,
Function<T, List<T>> getChildren, BiConsumer<T, List<T>> setChildren) {
Map<R, List<T>> parentMap = target.stream().collect(Collectors.groupingBy(getId));
List<T> result = new ArrayList<>();
target.forEach(tree -> {
List<T> parents = parentMap.get(getParentId.apply(tree));
if (parents == null) {
result.add(tree);
return;
}
for (T parent : parents) {
List<T> ch = getChildren.apply(parent);
if (ch == null) {
ch = new ArrayList<>();
ch.add(tree);
setChildren.accept(parent, ch);
} else {
Set<R> ids = ch.stream().map(getId).collect(Collectors.toSet());
if (!ids.contains(getId.apply(tree))) {
ch.add(tree);
setChildren.accept(parent, ch);
}
}
}
});
return result;
}