gpt4 book ai didi

swift - 如何基于分层数据创建 Swift 序列?

转载 作者:行者123 更新时间:2023-11-30 11:08:56 33 4
gpt4 key购买 nike

在我的各种项目中,我通常必须处理分层数据的迭代。尽管它很常见,但我不得不编写如此多的样板代码来完成它,这总是让我感到沮丧。

感谢 Swift 能够编写自定义 Sequence 类,我决定看看是否可以编写一个以可重用的方式实现这一目标的类。下面是我的结果。

我决定根据杰夫·阿特伍德的[关于鼓励发布自己的答案的自己的评论][1]在这里发布此内容,他说......

It is not merely OK to ask and answer your own question, it is explicitly encouraged [...] I do it all the time!

因此,我在这里提供此解决方案,希望对其他人搜索此网站时有所帮助。

享受吧! :)

最佳答案

如上所述,我编写了一个类,允许您迭代分层数据集,同时保持该层次结构有序。您可以通过指定一个或多个根元素(通过数组或变量)以及一个返回给定元素的子元素的闭包来完成此操作。

由于它是作为泛型实现的,因此如果您知道层次结构是同质的,则可以指定要使用的显式类型,但如果不是,请为该类型指定Any,然后在闭包中执行确定它是什么子类型的逻辑。

此外,通过递归实现,不仅以正确的层次顺序返回内容,而且还返回一个级别,以便您知道项目的深度。如果你不关心级别,只需在初始化序列时附加 .map{ $0.item } 即可直接提取项目。

这是自定义层次结构序列的代码...

struct HierarchicalSequence<TItem> : Sequence {

typealias GetChildItemsDelegate = (TItem) -> [TItem]?

init(_ rootItems:TItem..., getChildItems: @escaping GetChildItemsDelegate){
self.init(rootItems, getChildItems: getChildItems)
}
init(rootItems:[TItem], getChildItems: @escaping GetChildItemsDelegate){
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: @escaping GetChildItemsDelegate){
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 there's a child iterator, use it to see if there's a 'next' item
if let childIterator = childIterator {

if let childIteratorResult = childIterator.next(){
return childIteratorResult
}

// No more children so let's clear out the iterator
self.childIterator = nil
}

if nextIndex == items.count {
return nil
}

let item = items[nextIndex]
nextIndex += 1

// Set up the child iterator for the next call to 'next' but still return 'item' from this call
if let childItems = getChildItems(item),
childItems.count > 0 {

childIterator = Iterator(
level : level + 1,
items : childItems,
getChildItems : getChildItems)
}

return (level, item)
}
}

func makeIterator() -> Iterator {
return Iterator(level: 0, items: rootItems, getChildItems: getChildItems)
}
}

让我们看一个如何使用它的示例。首先,让我们从一些 JSON 数据开始......

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" }
]
}
]
}
]
"""

这是加载该数据的模型和代码

class Category : Codable {
let name : String
let subCategories : [Category]?
}

public let jsonData = jsonString.data(using: .utf8)!
var rootCategories = try! JSONDecoder().decode([Category].self, from: jsonData)

以下是如何使用序列获取所有类别及其深度...

let allCategoriesWithDepth = HierarchicalSequence(rootItems:rootCategories){ $0.subCategories }

for (depth, category) in allCategoriesWithDepth {
print("\(String(repeating: " ", count: depth * 2))\(depth): \(category.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

享受吧!

关于swift - 如何基于分层数据创建 Swift 序列?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52395955/

33 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com