Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/swift/17.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Swift 从字典数据构建树的最有效方法_Swift_Dictionary_Tree - Fatal编程技术网

Swift 从字典数据构建树的最有效方法

Swift 从字典数据构建树的最有效方法,swift,dictionary,tree,Swift,Dictionary,Tree,我有一本结构如下的词典:[Point:[Line]],其中: 点-包含两个坐标(X,Y)的自定义数据结构 Line—包含直线的第一个点和最后一个点的元组(点,点) 关键点-线的第一个点 因此,它是一个按第一点分组的行字典,如下所示: [a: [(a,b),(a,c)], b: [(b,c), (b,d)], c: [(c,d)] ] import Foundation typealias ProcessedLine = (UUID, [LineModel]) typealias Line

我有一本结构如下的词典:
[Point:[Line]]
,其中:

  • 点-包含两个坐标(X,Y)的自定义数据结构
  • Line—包含直线的第一个点和最后一个点的元组(点,点)
  • 关键点-线的第一个点
因此,它是一个按第一点分组的行字典,如下所示:

[a: [(a,b),(a,c)], b: [(b,c), (b,d)], c: [(c,d)] ]
import Foundation

typealias ProcessedLine = (UUID, [LineModel])
typealias LinePointDict = [Point: [Line]]

class LineAggregator {
    var builderStack: Stack<LineModel.LineModelBuilder>
    let startPointMap: LinePointDict
    var result: ProcessedLine
    var currentBuilder: (Point, LineModel.LineModelBuilder)?
    let startPoint: Point
    
    init(LineUid: UUID, startPointMap: LinePointDict, startPoint: Point) {
        self.builderStack = Stack<LineModel.LineModelBuilder>()
        self.startPointMap = startPointMap
        self.result = (LineUid, [])
        self.startPoint = startPoint
        self.currentBuilder = nil
    }
    
    func getLineAggregation() -> ProcessedLine {
        for Line in startPointMap[startPoint]! {
            var bldr = LineModel.LineModelBuilder(initialLineUuid: result.0)
            bldr = bldr.addLine(Line: Line)
            builderStack.push(bldr)
        }
        return aggregateModels()
    }
    
    func aggregateModels() -> ProcessedLine {
        while !builderStack.isEmpty() {
            takeBuilderFromStack()
            aggregateLine()
        }
        return result
    }
    
    /**
     * This functions pops Builder object from stack if the stack is not empty and sets it as a Current object to be processed.
     * @param object
     * @return
     */
    private func takeBuilderFromStack() {
        if(!builderStack.isEmpty()) {
            let curBuilder = builderStack.pop()!
            currentBuilder = (curBuilder.getLastElement(), curBuilder)
        }
    }
    
    private func aggregateLine() {
        
        if currentBuilder?.1.isLastAdded() ?? true {
            //If there is only one Line in the Line model
            if(currentBuilder!.1.isLastAddedLineLast()) {
                result.1.append(currentBuilder!.1.build())
                return
            }

            if(!builderStack.isEmpty()) {
                print("ERROR: Empty builder stack! Such situation should not happen. Pay attention at it.");
                builderStack.removeAll()
            }
            return
        }

        if currentBuilder != nil {
            for Line in startPointMap[currentBuilder!.0]! {
                var newBuilder = LineModel.LineModelBuilder(builder: currentBuilder!.1)
                newBuilder = newBuilder.addLine(Line: Line)
                if Line.isLast {
                    result.1.append(newBuilder.build())
                } else {
                    builderStack.push(newBuilder)
                }
            }
        }
        
    }
    
}
目标是将此字典转换为数据结构列表,如下所示:

[a: [(a,b),(a,c)], b: [(b,c), (b,d)], c: [(c,d)] ]
import Foundation

typealias ProcessedLine = (UUID, [LineModel])
typealias LinePointDict = [Point: [Line]]

class LineAggregator {
    var builderStack: Stack<LineModel.LineModelBuilder>
    let startPointMap: LinePointDict
    var result: ProcessedLine
    var currentBuilder: (Point, LineModel.LineModelBuilder)?
    let startPoint: Point
    
    init(LineUid: UUID, startPointMap: LinePointDict, startPoint: Point) {
        self.builderStack = Stack<LineModel.LineModelBuilder>()
        self.startPointMap = startPointMap
        self.result = (LineUid, [])
        self.startPoint = startPoint
        self.currentBuilder = nil
    }
    
    func getLineAggregation() -> ProcessedLine {
        for Line in startPointMap[startPoint]! {
            var bldr = LineModel.LineModelBuilder(initialLineUuid: result.0)
            bldr = bldr.addLine(Line: Line)
            builderStack.push(bldr)
        }
        return aggregateModels()
    }
    
    func aggregateModels() -> ProcessedLine {
        while !builderStack.isEmpty() {
            takeBuilderFromStack()
            aggregateLine()
        }
        return result
    }
    
    /**
     * This functions pops Builder object from stack if the stack is not empty and sets it as a Current object to be processed.
     * @param object
     * @return
     */
    private func takeBuilderFromStack() {
        if(!builderStack.isEmpty()) {
            let curBuilder = builderStack.pop()!
            currentBuilder = (curBuilder.getLastElement(), curBuilder)
        }
    }
    
    private func aggregateLine() {
        
        if currentBuilder?.1.isLastAdded() ?? true {
            //If there is only one Line in the Line model
            if(currentBuilder!.1.isLastAddedLineLast()) {
                result.1.append(currentBuilder!.1.build())
                return
            }

            if(!builderStack.isEmpty()) {
                print("ERROR: Empty builder stack! Such situation should not happen. Pay attention at it.");
                builderStack.removeAll()
            }
            return
        }

        if currentBuilder != nil {
            for Line in startPointMap[currentBuilder!.0]! {
                var newBuilder = LineModel.LineModelBuilder(builder: currentBuilder!.1)
                newBuilder = newBuilder.addLine(Line: Line)
                if Line.isLast {
                    result.1.append(newBuilder.build())
                } else {
                    builderStack.push(newBuilder)
                }
            }
        }
        
    }
    
}
  • (a,b)->(b,c)->(c,d)
  • (a,b)->(b,d)
  • (a,c)->(c,d)
  • 基本上是一棵树,根在第一点

    我尝试使用构建器模式和堆栈来执行此操作,因此我使用第一个点创建了一个构建器并放入堆栈,然后开始一个while循环,直到堆栈为空,然后在循环中删除当前构建器并基于最后和第一个点创建新的构建器,代码如下所示:

    [a: [(a,b),(a,c)], b: [(b,c), (b,d)], c: [(c,d)] ]
    
    import Foundation
    
    typealias ProcessedLine = (UUID, [LineModel])
    typealias LinePointDict = [Point: [Line]]
    
    class LineAggregator {
        var builderStack: Stack<LineModel.LineModelBuilder>
        let startPointMap: LinePointDict
        var result: ProcessedLine
        var currentBuilder: (Point, LineModel.LineModelBuilder)?
        let startPoint: Point
        
        init(LineUid: UUID, startPointMap: LinePointDict, startPoint: Point) {
            self.builderStack = Stack<LineModel.LineModelBuilder>()
            self.startPointMap = startPointMap
            self.result = (LineUid, [])
            self.startPoint = startPoint
            self.currentBuilder = nil
        }
        
        func getLineAggregation() -> ProcessedLine {
            for Line in startPointMap[startPoint]! {
                var bldr = LineModel.LineModelBuilder(initialLineUuid: result.0)
                bldr = bldr.addLine(Line: Line)
                builderStack.push(bldr)
            }
            return aggregateModels()
        }
        
        func aggregateModels() -> ProcessedLine {
            while !builderStack.isEmpty() {
                takeBuilderFromStack()
                aggregateLine()
            }
            return result
        }
        
        /**
         * This functions pops Builder object from stack if the stack is not empty and sets it as a Current object to be processed.
         * @param object
         * @return
         */
        private func takeBuilderFromStack() {
            if(!builderStack.isEmpty()) {
                let curBuilder = builderStack.pop()!
                currentBuilder = (curBuilder.getLastElement(), curBuilder)
            }
        }
        
        private func aggregateLine() {
            
            if currentBuilder?.1.isLastAdded() ?? true {
                //If there is only one Line in the Line model
                if(currentBuilder!.1.isLastAddedLineLast()) {
                    result.1.append(currentBuilder!.1.build())
                    return
                }
    
                if(!builderStack.isEmpty()) {
                    print("ERROR: Empty builder stack! Such situation should not happen. Pay attention at it.");
                    builderStack.removeAll()
                }
                return
            }
    
            if currentBuilder != nil {
                for Line in startPointMap[currentBuilder!.0]! {
                    var newBuilder = LineModel.LineModelBuilder(builder: currentBuilder!.1)
                    newBuilder = newBuilder.addLine(Line: Line)
                    if Line.isLast {
                        result.1.append(newBuilder.build())
                    } else {
                        builderStack.push(newBuilder)
                    }
                }
            }
            
        }
        
    }
    
    <代码>导入基础 typealias ProcessedLine=(UUID,[LineModel]) typealias LinePointDict=[Point:[Line]] 类线性集总器{ var builderStack:Stack 让startPointMap:LinePointDict var结果:ProcessedLine var currentBuilder:(点,LineModel.LineModelBuilder)? 让我们开始点:点 init(LineUid:UUID,startPointMap:LinePointDict,startPoint:Point){ self.builderStack=Stack() self.startPointMap=startPointMap self.result=(LineUid,[]) self.startPoint=startPoint self.currentBuilder=nil } func getLineAggregation()->ProcessedLine{ 对于startPointMap[startPoint]中的行{ var bldr=LineModel.LineModelBuilder(initialLineUuid:result.0) bldr=bldr.addLine(行:行) builderStack.push(bldr) } 返回聚合模型() } func aggregateModels()->ProcessedLine{ while!builderStack.isEmpty(){ takeBuilderFromStack() 聚合线() } 返回结果 } /** *如果堆栈不为空,此函数将从堆栈中弹出生成器对象,并将其设置为要处理的当前对象。 *@param对象 *@返回 */ 私有函数takeBuilderFromStack(){ 如果(!builderStack.isEmpty()){ 让curBuilder=builderStack.pop()! currentBuilder=(currentBuilder.getLastElement(),currentBuilder) } } 私有函数聚合线(){ 如果currentBuilder?.1.isLastAdded()??为真{ //如果线模型中只有一条线 如果(currentBuilder!.1.isLastAddedLineLast()){ 结果.1.追加(currentBuilder!.1.build()) 返回 } 如果(!builderStack.isEmpty()){ 打印(“错误:生成器堆栈为空!不应发生这种情况。请注意。”); builderStack.removeAll() } 返回 } 如果currentBuilder!=nil{ 对于startPointMap[currentBuilder!.0]中的行{ var newBuilder=LineModel.LineModelBuilder(生成器:currentBuilder!.1) newBuilder=newBuilder.addLine(行:行) if Line.isLast{ result.1.append(newBuilder.build()) }否则{ builderStack.push(新造船商) } } } } } 这个解决方案非常简单。它是有效的,但是我的字典中有大量的数据,而且组合的数量更大,所以这个算法非常慢,而且内存效率也不高

    主要的缓慢是由于向堆栈中添加数据和从堆栈中检索数据造成的,堆栈具有以下实现:

    import Foundation
    
    protocol Stackable {
        associatedtype Element
        func peek() -> Element?
        mutating func push(_ element: Element)
        @discardableResult mutating func pop() -> Element?
    }
    
    extension Stackable {
        var isEmpty: Bool { peek() == nil }
    }
    
    struct Stack<Element>: Stackable where Element: Equatable {
        private var storage = [Element]()
        func peek() -> Element? { storage.first }
        mutating func push(_ element: Element) { storage.append(element)  }
        mutating func pop() -> Element? { storage.popLast() }
        func size() -> Int { storage.count }
        func isEmpty() -> Bool { storage.isEmpty }
        mutating func removeAll() { storage.removeAll() }
    }
    
    extension Stack: Equatable {
        static func == (lhs: Stack<Element>, rhs: Stack<Element>) -> Bool { lhs.storage == rhs.storage }
    }
    
    extension Stack: CustomStringConvertible {
        var description: String { "\(storage)" }
    }
    
    extension Stack: ExpressibleByArrayLiteral {
        init(arrayLiteral elements: Self.Element...) { storage = elements }
    }
    
    <代码>导入基础 协议可堆叠{ 关联类型元素 func peek()->元素? 变异函数推送(u元素:元素) @discardableResult mutating func pop()->元素? } 扩展可堆叠{ var isEmpty:Bool{peek()==nil} } 结构堆栈:可堆叠,其中元素:Equatable{ 私有变量存储=[Element]() func peek()->元素?{storage.first} mutating func push(u元素:元素){storage.append(元素)} 变异func pop()->元素?{storage.popLast()} func size()->Int{storage.count} func isEmpty()->Bool{storage.isEmpty} 变异func removeAll(){storage.removeAll()} } 扩展堆栈:可均衡{ 静态func==(lhs:Stack,rhs:Stack)->Bool{lhs.storage==rhs.storage} } 扩展堆栈:CustomStringConvertible{ 变量说明:字符串{“\(存储)”} } 扩展堆栈:ExpressibleByArrayLiteral{ init(arrayliteralelements:Self.Element…{storage=elements} } 另一个瓶颈是复制数据和
    deinit
    方法


    我试图找到一个更好的解决方案,但还是什么都找不到。如有任何建议,我将不胜感激。谢谢。

    虽然builder模式很有用,但我认为在这种情况下,它只会使直接的解决方案复杂化,尽管正如您所看到的,我将介绍一些更复杂的解决方案,但它们是基于对第一个简单解决方案的性能优化

    正如您所注意到的,初始化和取消初始化类有点慢。实际上,最糟糕的部分是动态内存分配。类是强大的,肯定有其用途,但它们不是Swift工具箱中最快的工具。除非将方法设置为final,否则调用它们可能需要虚拟分派。这种情况也可能发生在协议中,这取决于他们声明的细节,尽管在这种情况下,它被称为“证人表重击”。但类最糟糕的地方是它们的实例几乎可以乱放在内存中的任何地方。这对处理器的片上cach来说简直是地狱