Собрать дерево из коллекций
Как можно получить дерево из следующего
Структура папок
name | folderId | parentId
test 1 | 1 | 2
test 2 | 2 | 0 //значит это корневой уровень
name 3 | 3 | 0 //значит это корневой уровень
name 4 | 4 | 1
name 5 | 5 | 1
Структура объектов
name | folderId
object 1 | 1
object 2 | 2
object 3 | 3
object 4 | 3
object 5 | 3
Я получаю
val folders = listOf(table1)
val objects = listOf(table2)
Из этого нужно получить List<TreeItem>
test 2 -> {
test 1 -> {
name 4
name 5
}
object 1
}
name 3 -> {
object 3
object 4
object 5
}
Модели данных
sealed class TreeItem {
class Folder(val folderInfo: TreeFolder, val childs: List<TreeItem>) : TreeItem()
class Object(val item: Object) : TreeItem()
}
data class TreeFolder(val name: String, folderId: Long, parentId: Long)
data class Object(val name: String, folderId: Long)
Ответы (2 шт):
Вот так я собрал дерево
fun getTreeObj(): Observable<List<TreeItem>> {
return Observables.zip(
treeFolderRepository.getTree(),
objectRepository.getObjects()
.toObservable()
.distinctUntilChanged()
) { folders, objects -> Pair(folders, objects) }
.observeOn(Schedulers.computation())
.map { treeItems ->
val objects = treeItems.second.toMutableList()
val folders = treeItems.first
if (folders.isEmpty()) {
return@map objects.map { TreeItem.Object(item = it) }
}
val treeFolderMap: MutableMap<Long, TreeItem.Folder> =
folders.map { TreeItem.Folder(folderInfo = it) }
.associateBy { it.folderInfo.folderId }
.toMutableMap()
treeFolderMap.forEach { folder ->
folder.value.childs.addAll(
objects.filter { it.first.folderId == folder.value.folderInfo.folderId }.let {
objects.removeAll(it)
it.map { TreeItem.Object(item = it) }
}
)
}
val iterator = treeFolderMap.iterator()
while (iterator.hasNext()){
iterator.next().apply {
treeFolderMap[value.folderInfo.parentId]?.let { parentFolder ->
parentFolder.childs.add(value)
iterator.remove()
}
}
}
return@map treeFolderMap.values.toList() as List<TreeItem>
}
.observeOn(AndroidSchedulers.mainThread())
}
Создаёшь структуру HashMap<String, TreeItem> где ключ это id папки и значение это объект папки
Далее добавляешь туда все папки После проходишь циклом каждый объект:
- Получаешь ID родительской папки
- Находишь папку по ID в HashMap
- Присоединяешь туда текущий элемент как дочерний Дальше проходишь по объектам(objects) и так-же цепляешь к нужным родителям.
В List<TreeItem> я так понял должны содержатся элементы которые находятся в корне, можешь объявить этот объект с самого начала и если у элемента нет родителя то добавляешь его сюда.
Должно получиться как-то так
public List<TreeItem> func(List<TreeItemInfo> folders, List<TreeItemInfo> objects) {
HashMap<String, TreeItem> foldersAndObjects = new HashMap<>();
List<TreeItem> root = new ArrayList<>();
// Ложим папки в hashMap по ID
for (TreeItemInfo folder : folders) {
foldersAndObjects.put(folder.getId(), new TreeItem(folder));
}
// Устанавливаем связи родитель-ребенок для папок
for (TreeItemInfo folder : folders) {
String parentID = folder.parentID(); // Получаем ID родителя
if (parentID == null) {
// Если родителя нет ложем узел в корень
root.add(new TreeItem(folder));
} else {
// Если ключ родителя есть, ищем его и присоединяем текущее значение как дочерний элемент
foldersAndObjects.get(parentID).setChild(new TreeItem(folder));
}
}
// Добавляем объекты в папки или в root
for (TreeItemInfo object : objects) {
String parentID = object.parentID();
if (parentID == null) {
root.add(new TreeItem(object));
} else {
foldersAndObjects.get(parentID).setChild(new TreeItem(object));
}
}
// Возвращаем список корневых элементов
return root;
}
TreeItem - это должна быть структура у которой есть значения: значение узла, ссылки на родителя и дочерние узлы
TreeItemInfo - Это грубо говоря объект содержаний информацию по которой можно получить ID родителя и по его значению можно создать узел TreeItem