Swift CustomStringConvertible与复杂类型

时间:2019-01-28 01:14:09

标签: swift

我希望CustomStringConvertible为我提供一个节点的描述,特别是它包含的边缘。

对于背景知识,我一直致力于图论并创建了一个节点:

class Node : CustomStringConvertible {
    // unique identifier required for each node
    var identifier : Int
    var distance : Int = Int.max
    var edges = [Edge]()
    var visited = false

    var description: String {
        return "identifier: " + identifier.description + ", Edges: " + ( "edgesString" )
    }

    init(visited: Bool, identifier: Int, edges: [Edge]) {
        self.visited = visited
        self.identifier = identifier
        self.edges = edges
    }

    static func == (lhs: Node, rhs: Node) -> Bool {
        return lhs.identifier == rhs.identifier
    }
}

有边缘

class Edge {
    var from: Node // does not actually need to be stored!
    var to: Node
    var weight: Int
    var description : String {
        return "from: " + from.description + ", to: " + to.description + ", weight: " + weight.description
    }
    init(to: Node, from: Node, weight: Int) {
        self.to = to
        self.weight = weight
        self.from = from
    }
}

我可以轻松地打印出每个节点的每个边缘

  

testGraph.nodes.forEach {$ 0.edges.forEach {print($ 0.description)}}

但是我无法通过节点的描述来实现in。

我试图为每条语句写与我相同的内容

var description: String {
    var edgesString = String()
    edges.forEach{  edgesString.append($0.description)}
    return "identifier: " + identifier.description + ", Edges: " + ( edgesString )
}

但是在这种情况下,执行给出了EXC_BAD_ACCESS,实际上我无法获取任何代码来完成并提供节点及其包含的边的描述。

如何完成对节点的描述字符串,然后继续描述边缘?

1 个答案:

答案 0 :(得分:1)

似乎您的description代码会导致Node.descriptionEdge.description无限循环。

Node对每个边调用Edge.description,对边Edge对其来往节点调用Node.description。如果图形具有圆形连接而不是星形连接,则将导致无限绕行。

一种简单的方法是Edge.description仅显示Node.identifier而不是详细的描述。

class Edge {
    var from: Node // does not actually need to be stored!
    var to: Node
    var weight: Int
    var description : String {
        return "{ Edge, from: \(from.identifier), to: \(to.identifier), weight: \(weight) }"
    }
    init(to: Node, from: Node, weight: Int) {
        self.to = to
        self.weight = weight
        self.from = from
    }
}
class Node : CustomStringConvertible {
    // unique identifier required for each node
    var identifier : Int
    var distance : Int = Int.max
    var edges = [Edge]()
    var visited = false

    var description: String {
        let edgesString = edges.map { $0.description }.joined(separator: ", ")
        return "{ Node, identifier: \(identifier), Edges: [\(edgesString)] }"
    }

    init(visited: Bool, identifier: Int, edges: [Edge]) {
        self.visited = visited
        self.identifier = identifier
        self.edges = edges
    }

    static func == (lhs: Node, rhs: Node) -> Bool {
        return lhs.identifier == rhs.identifier
    }
}

let rootNode = Node(visited: false, identifier: 10, edges: [])
var edges: [Edge] = []
for i in 0..<3 {
    let node = Node(visited: false, identifier: i, edges: [])
    let edge = Edge(to: node, from: rootNode, weight: i)
    edges.append(edge)
}
rootNode.edges = edges

print(rootNode)
// { Node, identifier: 10, Edges: [{ Edge, from: 10, to: 0, weight: 0 }, { Edge, from: 10, to: 1, weight: 1 }, { Edge, from: 10, to: 2, weight: 2 }] }

如果您要搜索和打印所有节点,则最好再做一个功能来做到这一点。

它应该记住您已经访问过哪个节点(或者,如果可以,请使用visited成员),并尝试不访问那些访问过的节点。