Generate section headers from dictionary [Swift 3]

810 views Asked by At

I have an array of dictionaries with the following type of structure (which is already sorted) :

[
 [
  "id": 1,
  "name": "ItemA",
  "url": "http://url.com"
 ],
 [
  "id": 32,
  "name": "ItemB",
  "url": "http://url.com"
 ],
 ...
]

Declared as an array of dictionaries for AnyObject :

var arrayApps = [[String:AnyObject]]()

This array of dictionaries is generated using SwiftyJson :

[..]
if let resData = swiftyJsonVar["data"].arrayObject {
  self.arrayItems = resData as! [[String:AnyObject]]
}
[..]

My Goal is to display those items in sections by using the sections headers but after trying to figure it out and looking for an answer, i'm unable to move on. I've tried to groupe the dictionaries by letters to get a result like this:

[
  "A":{[foo1],[foo2]},
  "D":{[foo3],[foo5]},
  "F":{[foo4],[foo6]}
  ...
]

But no luck, i've always ended up with errors because my array contains "Optionals".

In summary : How can I generate Alphabetical section headers based on the name inside a TableView using an array of dictionaries not grouped like the one given above in Swift 3 ?

Thank you in advance !!

1

There are 1 answers

4
Emptyless On BEST ANSWER

You can use the .sorted(by: ) method of Array to compare to elements of you array with each other.

This yields a sortedArray:

let sortedArray = arrayOfApps.sorted(by: {($0["name"] as! String) <= ($1["name"] as! String)})

This will crash if the itemName is not a String but I left it to you to handle any errors. For example changing it to:

$0["name"] as? String ?? ""

EDIT: // Removed examples and added extension to create desired result

I found one of my old projects where I wrote such extension. Changed it a bit to suit your needs, tell me if it needs some change still:

extension Array {
    func sectionTitlesForArray(withName name: (Element) -> String) -> Array<(title: String, elements: NSMutableArray)> {
        var sectionTitles = Array<(title: String, elements: NSMutableArray)>()

        self.forEach({ element in
            var appended = false
            sectionTitles.forEach({ title, elements in
                if title == name(element) {
                    elements.add(element)
                    appended = true
                }
            })
            if appended == false {
                sectionTitles.append((title: name(element), elements: [element]))
            }
        })

        return sectionTitles

    }
}

// Usage single letter as Section title: 
let sectionTitles = arrayOfApps.sectionTitlesForArray(withName: {
    let name = $0["name"] as! String
    return String(name[name.startIndex])
})

// Quick dirty pretty-print:
sectionTitles.forEach({ sectionTitle in
    print("Section title: \(sectionTitle.title) \n")
    sectionTitle.elements.forEach({ object in
        let element = object as! Dictionary<String,Any>
        print("Element name: \(element["name"]!)")
    })
    print("")
})