У меня есть плоский список, в котором у каждого элемента есть parentId, а id - это мой код, который преобразует этот список в дерево.
, это класс Node
class Node: DownloadingItemsProvider {
var children: [Node] = []
weak var parent: Node?
var associatedObject: AppListItem?
var level = 0
init(associatedObject: AppListItem) {
self.associatedObject = associatedObject
}
func preorder(level: Int = 0) -> [Node] {
self.level = level
return [self] + children.flatMap { $0.preorder(level: level + 1) }
}
}
. Это метод, который преобразуетплоский список из AppListItem
в плоский список узлов с правильным упорядочением, с предварительным заказом
func getRootsFrom(list: [AppListItem]) -> [Node] {
var dict: [String : Node] = [:]
list.forEach { (appItem) in
dict[appItem.uuid] = Node(associatedObject: appItem)
}
dict.values.forEach { (node) in
if let value = dict[node.associatedObject?.parentUUID ?? ""] {
let proposedParent = value
node.parent = proposedParent
proposedParent.children.append(node)
proposedParent.children.sort(by: {$0.associatedObject?.sort ?? "" < $1.associatedObject?.sort ?? ""})
}
}
var roots: [Node] = []
for root in dict.values.filter({$0.parent == nil}).sorted(by: {$0.associatedObject?.sort ?? "" < $1.associatedObject?.sort ?? ""}) {
roots.append(contentsOf: root.preorder())
}
return roots
}
Так что в основном у меня есть несколько листов этого дерева, и мне нужно показать поддерево, как приложение Finder, в macOS
вот мое решение
var dataSource: [DownloadingItemsProvider] = []
let sortedItems = filteredRoot.isEmpty ? root : filteredRoot
let downloadingListItems = sortedItems.filter { (localItem) -> Bool in
return downloadingURLItems.contains(where: {$0.key == localItem.associatedObject?.downloadUrl})
}
if downloadingListItems.isEmpty {
return dataSource
}
var list: Set<AppListItem> = []
for item in downloadingListItems {
for row in getItemsHierachy(for: item.associatedObject?.uuid ?? "") {
list.insert(row)
}
}
var tempList: [Node] = []
for item in (filteredRoot.isEmpty ? root : filteredRoot) {
if let object = item.associatedObject, list.contains(object) {
tempList.append(item)
if object.downloadUrl == nil {
object.headerTitle = String(repeating: ".", count: item.level) + (object.title ?? "")
dataSource.append(item)
} else {
if let downloadObject = DownloadManager.shared.ongoingDownloads[object.downloadUrl ?? ""]?.object {
dataSource.append(downloadObject)
}
}
}
}
_ = configureSize(with: tempList.first?.associatedObject?.parentUUID, listableItems: Dictionary.init(grouping: tempList.map({$0.associatedObject}).compactMap({$0}), by: {$0.parentUUID ?? "root"}), isDownloading: true)
filteredRoot = tempList
return dataSource
поэтому сначала я получаю иерархию каждого листа и добавляю это в набор предметов, поэтому в конце у меня есть список всех необходимых предметов, которые нужно показать, но беззная правильное упорядочение, поэтому я делаю цикл for в своем плоском предварительно упорядоченном списке и проверяю, соответствует ли какой-либо элемент любому элементу в моем наборе, и добавляю его в возвращаемый список.Проблема в том, что это работает очень долго для 400 элементов, а также после того, как каждый элемент был загружен или отменен, мне нужно повторно запустить этот код, чтобы получить правильный список, который будет отображаться, поэтому я не понимаю, как приложение Finder работает так быстро, и как онипоказать данные, это простой tableView?
Спасибо в совете.
EDITED
Как я понял, я могу сохранить некоторые для цикла, если яЯ могу создать поддерево из листьев, поэтому мне не нужно делать эту иерархию, и фильтрация
вот что-то, возможно, мне нужно Python (yield): все пути от листьев к корню в дереве
но, к сожалению, я не знаком с Python.