How to make headers in alphabetical order as a table with a mutable data source

I store view controller strings in an array of strings. I am importing this string array as a data source in my table view. It all works smoothly. But now I would like to sort the table view and add the section headers. The section title should be from the alphabet, the value section lines should be all the lines from the array, starting with the section title letter.

I know how I can achieve this with static arrays. But how can I make it show only sections that also have rows (rows in an array)? And how can I make it so that it generates a new section while saving a new line with a letter that does not yet exist in the sections?

I hope I explained it quite accurately. I tried to solve this problem for a long time. It would be great if someone could help me.

Here are some code snippets:

class OverViewController: UIViewController { @IBOutlet weak var tableView: UITableView! @IBOutlet weak var addButton: UIBarButtonItem! @IBOutlet weak var editButton: UINavigationItem! var kontaktListe = Telefonbuch.loadArray() var sections = [[String]]() var collation = UILocalizedIndexedCollation.currentCollation() override func viewDidLoad() { super.viewDidLoad() tableView.dataSource = self configureSectionData() tableView.reloadData() } func configureSectionData() { let names = kontaktListe.map{$0.name} let selector: Selector = "description" sections = Array(count:collation.sectionTitles.count, repeatedValue: []) let sortedObjects = collation.sortedArrayFromArray(names, collationStringSelector: selector) for object in sortedObjects { let sectionNumber = collation.sectionForObject(object, collationStringSelector: selector) sections[sectionNumber].append(object as! String) } } 

I load the var kontaktListe = Telefonbuch.loadArray() object and get the name let names = kontaktListe.map{$0.name} . And I would like to get rows to sort and add.

+5
source share
3 answers

I would change the way you store your contacts using a dictator with the initial letters as keys and put the names corresponding to this initial letter in a subarray:

 contacts = ["A": ["Anton", "Anna"], "C": ["Caesar"]] 

I simplified the contact path here (in the form of strings), but you got the concept.

I would also store the letter section number in a separate array as follows:

 letters = ["A", "C"] 

Keep the array sorted and organized, so check after each insert / delete / update. This is not part of the implementation of the table view. I would make Viewcontroller a phone book delegate, so that you can run a method similar to updating from the phone book to update the table.

How to get data for a data source:

number of sections:

 letters.count 

section heading for section with index i equals

 letters[i] 

the number of cells in section i equals

 contacts[letters[i]].count 

and the content for a specific cell c in section i:

 contacts[letters[i]][c] 

Feel free to ask additional questions if something else is not clear.

UPDATE - How to generate arrays:

I don't need data to sort, if you have already sorted it, you can delete the sort lines below ...

 let data = ["Anton", "Anna", "John", "Caesar"] // Example data, use your phonebook data here. // Build letters array: var letters: [Character] letters = data.map { (name) -> Character in return name[name.startIndex] } letters = letters.sort() letters = letters.reduce([], combine: { (list, name) -> [Character] in if !list.contains(name) { return list + [name] } return list }) // Build contacts array: var contacts = [Character: [String]]() for entry in data { if contacts[entry[entry.startIndex]] == nil { contacts[entry[entry.startIndex]] = [String]() } contacts[entry[entry.startIndex]]!.append(entry) } for (letter, list) in contacts { list.sort() } 

For Swift 3 :

 let data = ["Anton", "Anna", "John", "Caesar"] // Example data, use your phonebook data here. // Build letters array: var letters: [Character] letters = data.map { (name) -> Character in return name[name.startIndex] } letters = letters.sorted() letters = letters.reduce([], { (list, name) -> [Character] in if !list.contains(name) { return list + [name] } return list }) // Build contacts array: var contacts = [Character: [String]]() for entry in data { if contacts[entry[entry.startIndex]] == nil { contacts[entry[entry.startIndex]] = [String]() } contacts[entry[entry.startIndex]]!.append(entry) } for (letter, list) in contacts { contacts[letter] = list.sorted() } 

I ran the code on the playground and got the following outputs for

letters:

 ["A", "C", "J"] 

contacts:

 ["J": ["John"], "C": ["Caesar"], "A": ["Anton", "Anna"]] 
+11
source

For Swift 3 . Thank @Stefan Here is my version with Set

 var tableViewSource: [Character : [String]]! var tableViewHeaders: [Character]! let data = ["Anton", "Anna", "John", "Caesar"] func createTableData(wordList: [String]) -> (firstSymbols: [Character], source: [Character : [String]]) { // Build Character Set var firstSymbols = Set<Character>() func getFirstSymbol(word: String) -> Character { return word[word.startIndex] } wordList.forEach {_ = firstSymbols.insert(getFirstSymbol(word: $0)) } // Build tableSourse array var tableViewSourse = [Character : [String]]() for symbol in firstSymbols { var words = [String]() for word in wordList { if symbol == getFirstSymbol(word: word) { words.append(word) } } tableViewSourse[symbol] = words.sorted(by: {$0 < $1}) } let sortedSymbols = firstSymbols.sorted(by: {$0 < $1}) return (sortedSymbols, tableViewSourse) } func getTableData(words: [String]) { tableViewSource = createTableData(wordList: words).source tableViewHeaders = createTableData(wordList: words).firstSymbols } getTableData(words: data) print(tableViewSource) // ["J": ["John"], "C": ["Caesar"], "A": ["Anna", "Anton"]] print(tableViewHeaders) // ["A", "C", "J"] 
+4
source

I did this in one cycle, a bit ( Swift 4 ):

 struct ContactData { let longName: String let phones: [String] let thumbnailImageData: Data? } var contacts = [ContactData]() var tableViewSource = [Character : [ContactData]]() var headerTitles = [Character]() func createContactsData(completionHandler: @escaping () -> Swift.Void) { contacts = extractContacts() // convert CNContact to custom ContactData tableViewSource.removeAll() var prevChar: Character? var currentBatch: [ContactData]! contacts.forEach { contact in guard let firstChar = contact.longName.first else { return } if prevChar != firstChar { if prevChar != nil { tableViewSource[prevChar!] = currentBatch } prevChar = firstChar currentBatch = [ContactData]() } currentBatch.append(contact) } let allKeys = Array(tableViewSource.keys) let sortedSymbols = allKeys.sorted(by: {$0 < $1}) headerTitles = sortedSymbols completionHandler() } 
0
source

Source: https://habr.com/ru/post/1246790/


All Articles