swiftdictionary

Retrieve value from known keys in simple nested Dictionary


I have a dictionary of Strings, like chapters or table of contents for an aircraft manual, like this:

let ataChapter: [[String:String]:Dictionary] = [
    ["21":"Air Conditioning"] : [
        "21-31":"Pressure control and monitoring",
        "21-51":"Pack flow control",
        "21-52":"Air cooling system",
        "21-55":"Emergency ram air inlet",
        "21-61":"Pack temperature control",
        "21-63":"Cockpit and cabin temperature control"],
    ["22":"Autoflight"] : [
        "22-01":"Overhead panel",
        "22-05":"FMA",
        "22-10":"A/P and F/D",
        "22-30":"Autothrust",
        "22-83":"FMGC"]
]

First level string pair is the chapter number and title, second level is each chapters code and its associated aircraft system. The dictionary will be quite long (this is just a few rows from it) but the format is the same so I don't see a reason for a struct, given its simple construction.

Now, I will have a known exact system code - something like "21-52-30A" and with that String I need to find and return:

  1. the chapter name, e.g. "Air Conditioning" (value) from the top level value because the first 2 characters are 21, and

  2. the system name, e.g. "Air cooling system" (value) from the second level because the first 4 characters are "21-52".

In other words, how do I match the key from the top level to the first 2 characters in my known string, and the key from the second level to the first 4 characters, and return their respective values?

I've done this so far:

for (keys, values) in ataChapter {
    for (item) in keys {
        print(item.value)
    }

    for (chapter) in values {
        print(chapter.value)
    }
}

I understand the concept of this simple loop, and with it I obviously get all the string values back but I'm a beginner at this stuff and can't figure out the matching part and return only the values matching the code in my String.


Solution

  • If you insist on keeping your dictionary structure here is one way to do it

    let chapterKey = "21"
    let sectionKey = "21-52"
    
    if let chapter = ataChapter.first(where: { $0.key[chapterKey] != nil }),
       let section = chapter.value.first(where: { $0.key == sectionKey }) {
        print(chapter.key.values.first!)
        print(section.key, section.value)
    }
    

    Air Conditioning
    21-52 Air cooling system

    If you don't like the forced unwrapping you could include

    let chapterTitle = chapter.key.values.first,
    

    in the if condition and use that variable instead.

    Another solution is to use custom types instead of the dictionary construction. For example

    struct Section {
        let key: String
        let title: String
    }
    
    struct Chapter {
        let key: String
        let title: String
        let sections: [Section]
    }
    

    and then have an array of Chapter. The search code would be pretty similar to what we already have but the advantage of a custom structure is that we can add functionality to it so for instance implement a subscript in Chapter:

    subscript(_ sectionKey: String) -> Section? {
        sections.first(where: { $0.key == sectionKey })
    }
    

    If we also use a dictionary instead of an array with the chapter key as key

    let chapters: [String: Chapter] = ...
    

    then the search code could be simplified to

    if let chapter = chapters[chapterKey], let section = chapter[sectionKey] {
        print(chapter.title)
        print(section.key, section.title)
    }