0

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 !!

blackjak231
  • 174
  • 1
  • 11

1 Answers1

2

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("")
})
Emptyless
  • 2,964
  • 3
  • 20
  • 30
  • Thanks for your answer, but this part is already covered :) The API that returns the data already sorts it and i was able to sort on the app side. My issue is on how to group them by the first letter of the "name" to add section headers. Thanks anyway for your answer :) – blackjak231 Jan 07 '17 at 21:38
  • I have changed my answer to reflect what i think was your question - If you are 100% sure that the Array is sorted alphabetically to the name value than it might be further optimized but this will do for 99% of normal cases :-) – Emptyless Jan 08 '17 at 00:22
  • I haven't had time to try it out, been a busy day. As soon as i'll be able to try it I'll let you know ! :) – blackjak231 Jan 08 '17 at 20:26
  • Worked like a charm :) Still new to iOS development so i'm not all that clear on the extensions, but i managed to do what i want with what you gave me ! Thanks a lot ! – blackjak231 Jan 10 '17 at 10:43