Как указано выше, я написал класс, который позволяет вам перебирать иерархический набор данных, сохраняя эту иерархию в порядке.Это делается путем указания корневых элементов и замыкания, которое возвращает дочерние элементы для каждого из корней.Реализация через рекурсию не только возвращает вещи в правильном иерархическом порядке, но также возвращает уровень, чтобы вы знали, насколько глубоки были элементы.
Вот код ...
struct HierarchicalSequence<TItem> : Sequence {
typealias GetChildItemsDelegate = (TItem) -> [TItem]
init(rootItems:[TItem], getChildItems: GetChildItemsDelegate? = nil){
self.rootItems = rootItems
self.getChildItems = getChildItems
}
let rootItems : [TItem]
let getChildItems : GetChildItemsDelegate?
class Iterator : IteratorProtocol {
typealias Element = (level:Int, item:TItem)
init(level:Int, items:[TItem], getChildItems: GetChildItemsDelegate? = nil){
self.level = level
self.items = items
self.getChildItems = getChildItems
}
let level : Int
let items : [TItem]
let getChildItems : GetChildItemsDelegate?
private var nextIndex = 0
var childIterator:Iterator?
func next() -> Element? {
if let childIterator = childIterator {
if let childIteratorResult = childIterator.next(){
return childIteratorResult
}
self.childIterator = nil
}
if nextIndex == items.count {
return nil
}
let item = items[nextIndex]
nextIndex += 1
if let getChildItems = getChildItems {
let childItems = getChildItems(item)
childIterator = Iterator(
level : level + 1,
items : childItems,
getChildItems : getChildItems)
}
return (level, item)
}
}
func makeIterator() -> Iterator {
return Iterator(level: 0, items: rootItems, getChildItems: getChildItems)
}
}
И вот пример его использования.
public let jsonString = """
[
{
"name" : "Section A",
"subCategories" : [
{
"name" : "Category A1",
"subCategories" : [
{ "name" : "Component A1a" },
{ "name" : "Component A1b" }
]
},
{
"name" : "Category A2",
"subCategories" : [
{ "name" : "Component A2a" },
{ "name" : "Component A2b" }
]
}
]
},
{
"name" : "Section B",
"subCategories" : [
{
"name" : "Category B1",
"subCategories" : [
{ "name" : "Component B1a" },
{ "name" : "Component B1b" }
]
},
{
"name" : "Category B2",
"subCategories" : [
{ "name" : "Component B2a" },
{ "name" : "Component B2b" }
]
}
]
}
]
"""
public let jsonData = jsonString.data(using: .utf8)!
class Category : Codable {
required init(from decoder: Decoder) throws {
let values = try decoder.container(keyedBy: CodingKeys.self)
name = try values.decode(String.self, forKey: .name)
subCategories = try values.decodeIfPresent([Category].self, forKey: .subCategories) ?? []
}
let name : String
let subCategories : [Category]
}
var myJsonCategories = try! JSONDecoder().decode([Category].self, from: jsonData)
let hierarchicalCategories = HierarchicalSequence(rootItems:myJsonCategories){
category in category.subCategories
}
for categoryInfo in hierarchicalCategories {
print("\(String(repeating: " ", count: categoryInfo.level * 2))\(categoryInfo.level):\(categoryInfo.item.name)")
}
И, наконец, вот результат ...
0:Section A
1:Category A1
2:Component A1a
2:Component A1b
1:Category A2
2:Component A2a
2:Component A2b
0:Section B
1:Category B1
2:Component B1a
2:Component B1b
1:Category B2
2:Component B2a
2:Component B2b
Я хотел бы получить некоторые отзывы об этом, чтобы увидеть, если естьвозможно, более простой способ добиться этого, но я должен сказать, что я доволен производительностью.
Дай мне знать, что ты думаешь!