1

This question has previously been posted, like Alphabetical sections in table table view in swift, but I can't really wrap my head around it when I try to implement it into my own code.

I have the standard functions to get the alphabetic sections in place:

func numberOfSections(in tableView: UITableView) -> Int {
    return collation.sectionTitles.count
}

func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
    return collation.sectionTitles[section]
}

func sectionIndexTitles(for tableView: UITableView) -> [String]? {
    return collation.sectionIndexTitles
}

func tableView(tableView: UITableView!, sectionForSectionIndexTitle title: String!, atIndex index: Int) -> Int {
    return collation.section(forSectionIndexTitle: index)
}

I have an array that has collected data from the local contact book on the app: var contactArray = [ExternalAppContactsBook](). ExternalAppContactsBook looks like this:

class ExternalAppContactsBook {
    var firstName = ""
    var lastName = ""
    var phoneNumber = ""
    var company = ""
}

I would like to list the object in alphabetical order based on lastName under their respective sections. I get that the magic happens in cellForRowAt but I can't seem to get it right. The article above maps a string to a dictionary, but I need an object, which complicates things.

I have mapped a dictionary by breaking out lastName from the object into its own array like this:

var lastNameArray = [String]()

for index in self.contactArray {
    lastNameArray.append(index.lastName)
}

let groupedDictionary = Dictionary(grouping: lastNameArray, by: {String($0.prefix(1))})
let keys = groupedDictionary.keys.sorted()
var mapedSection = [Section]()
mapedSection = keys.map{Section(letter: $0, names: groupedDictionary[$0]!.sorted())}

But how do I use it?

Could someone give me a few pointers to get started?

EDIT It works this way, but I'm unsure if it's gonna work to arrange the object in the tableview:

for index in self.contactArray {
    lastNameArray.append(index.lastName)
}

if let c = self.contactArray {
    let groupedDictionary = Dictionary(grouping: lastNameArray, by: {String($0.prefix(1))})
    let keys = groupedDictionary.keys.sorted()
    var mapedSection = [Section]()
    mapedSection = keys.map{Section(letter: $0, names: groupedDictionary[$0]!.sorted())}
    print("☎️", mapedSection)
}

The print shows:

Section(letter: "H", names: ["Haro", "Higgins"]), Section(letter: "T", names: ["Taylor"])

...and so on. I think there still might be a problem when actually populating the tableView.

Whipper Snapper
  • 185
  • 2
  • 11

1 Answers1

1

You have to group contactArray and sections (this name is sufficient) must become the data source array

var sections = [Section]()

and you have to declare Section

struct Section {
    let letter : String
    let people : [ExternalAppContactsBook]
}

let groupedDictionary = Dictionary(grouping: contactArray, by: {String($0.lastName.prefix(1))})
let keys = groupedDictionary.keys.sorted()
sections = keys.map{Section(letter: $0, people: groupedDictionary[$0]!.sorted(by: {$0.lastName < $1.lastName})}

According to my answer in the linked question the datasource and delegate methods are

func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    return sections[section].people.count
}

func numberOfSectionsInTableView(tableView: UITableView) -> Int{
    return sections.count
}

func sectionIndexTitles(for tableView: UITableView) -> [String]? {
    return sections.map{$0.letter}
}

func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
    return sections[section].letter
}
vadian
  • 274,689
  • 30
  • 353
  • 361
  • Thanks. But changing `grouping: lastNameArray` to object `contactArray` gave error on `sections = keys...` "Referencing instance method 'sorted()' on 'Sequence' requires that 'ExternalAppContactsBook' conform to 'Comparable'". I removed `.sorted()` and it gave error "Cannot convert value of type '[ExternalAppContactsBook]' to expected argument type '[String]'" Sidenote: `Section()` simply consists of `struct Section { let letter : String let names : [String] }` Is that sufficient? – Whipper Snapper Oct 15 '19 at 20:20
  • You have to adopt `Comparable`. I updated the answer – vadian Oct 15 '19 at 20:45
  • Thanks a lot for helping me out. I still get the same error though, even after implementing the changes in `ExternalAppContactsBook`: "Cannot convert value of type '[ExternalAppContactsBook]' to expected argument type '[String]'" Does it have to do with the way `Section()` looks like? `lastName` is definitely a `String`, but when adding a prefix it becomes a `Dictionary`, right? Perhaps that's the issue? – Whipper Snapper Oct 16 '19 at 06:54
  • The code in the answer is supposed to work. Where do you get the error? – vadian Oct 16 '19 at 07:00
  • Sorry for late response, have been sitting on my own trying to fix it. :/ Anyway, the error is on the line `mapedSection = keys.map{Section(letter: $0, names: groupedDictionary[$0]!.sorted())}`. To be more specific, `.sorted()` is underlined in red. But removing `sorted()` still produce error. I have tried the code in different parts of the class with no success. – Whipper Snapper Oct 17 '19 at 11:21
  • `contactArray.lastName` is a `string` so I don't see why it should be an issue... – Whipper Snapper Oct 17 '19 at 11:28
  • I edited the post above. It works the way I tried above. Question is if that's enough for populating the `tableView` in a correct way... – Whipper Snapper Oct 17 '19 at 11:36
  • I see the issue. Please see my updated answer. And see also the `sorted(by` API to sort the contacts without adding conformance to `Comparable`. – vadian Oct 17 '19 at 11:44
  • Seriously, thank you so much for helping me out @vadian. I got it to working now! Thanks for taking the time. Big gold star to you! :D – Whipper Snapper Oct 17 '19 at 12:34
  • I added it to `cellForRowAt` like this: `contactLastName = mapedSection[indexPath.section].people[indexPath.row].lastName` and so on. Works great, looks clean! :) – Whipper Snapper Oct 17 '19 at 12:36