stevenpcurtis
stevenpcurtis

Reputation: 2001

Unwrapping dictionary values Swift

I'm creating an adjacency list in Swift, storing an array of nodes. However, when adding an edge from an existing node I need to check if the from key exists in any of the children, and if it does check if the to value exists in the same. It seems to be a mess s.t.

func addEdge(from: String, to: String) {
//the full code for addEdge is incomplete here
    if (children.contains{ $0.nodes[from] != nil}) {
    for child in children {
        if (child.nodes[from] != nil) {
            if (!(child.nodes[from]?.contains{$0 == to})!){
                child.nodes[from]?.append(to)
            }
        }
    }
    }
    }

Children is

var children = [Node]()

and Node is

class Node: Hashable {
    var nodes = [String:[String]]()
    var hashValue: Int{ return nodes.hashValue }
    static func == (lhs: Node, rhs: Node) -> Bool {
        return lhs.nodes.keys == rhs.nodes.keys
    }
}

Now it works, but seems really ugly. There must be a better way in Swift, but what is it?

Upvotes: 0

Views: 88

Answers (2)

Serhii Didanov
Serhii Didanov

Reputation: 2348

Try something like:

if (children.contains{ $0.nodes[from] != nil}) {
    children.filter { $0.nodes[from] != nil }.
       compactMap { $0.nodes[from] }.
       filter { !($0.nodes[from]!.contains{$0 == to}) }.
       forEach { $0.nodes[from]?.append(to) }
}

Upvotes: 0

M. Ullah
M. Ullah

Reputation: 96

Assuming that you do not wish to change the way you have implemented the above code but want to improve readability, you can utilise if let and optional chaining to make your code cleaner and more readable.

func addEdge(from: String, to: String) {
//the full code for addEdge is incomplete here
    if children.contains{ $0.nodes[from] != nil } {
        for child in children {
            if let fromNode = child.nodes[from], fromNode.contains{$0 == to} {
                fromNode.append(to)
            }
        }
    }
}

Swift Optional Chaining

Upvotes: 1

Related Questions