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

问题描述 投票:0回答:1

在我的各种项目中,我必须处理分层数据。在某些情况下,我需要通过使用递归函数爬行层次结构来“压扁”该数据。总是让我感到沮丧的是,我必须编写所有代码来实现我觉得应该简单的东西。

由于Swift具有编写自定义Sequence类的能力,因此我决定看看是否可以编写一个能够以可重用的方式实现此目标的类。

经过StackOverflow的搜索,收集各个部分并最终找出迭代器的递归后,我成功地找到了一个可行的解决方案。由于它是从这里诞生的,我想回馈社区并分享它,希望它可以帮助其他人的网站总是帮助我的方式。

也就是说,为了遵循SO的做法,我将其作为问题/答案发布。因此,请参阅下文。

请享用! :)

swift sequence hierarchy hierarchical-data
1个回答
0
投票

如上所述,我编写了一个类,允许您迭代一组分层数据,同时保持该层次结构的顺序。您可以通过指定根元素和一个返回每个根的子元素的闭包来完成此操作。通过递归实现,不仅以正确的层次结构顺序返回事物,而且还返回一个级别,以便您知道项目的深度。

这是代码......

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

我喜欢这方面的一些反馈,看看是否有更简单的方法来实现这一点,但我不得不说我对表现感到满意。

让我知道你在想什么!

© www.soinside.com 2019 - 2024. All rights reserved.