How to Get Alphabetic Tableview Sections from an Object

How do I get alphabetic tableView sections from an object

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
}

Alphabetical sections in table table view in swift

You can put your arrays with names into dictionary with letter keys.

For example

var names = ["a": ["and", "array"], "b": ["bit", "boring"]]; // dictionary with arrays setted for letter keys

then you need to access values in your dictionary in the next way

func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int{
return names[usernames[section]].count; // maybe here is needed to convert result of names[...] to NSArray before you can access count property
}

func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell{

let cellID = "cell"

let cell: UITableViewCell = self.tv.dequeueReusableCellWithIdentifier(cellID) as UITableViewCell

cell.textLabel?.text = names[usernames[indexPath.section]][indexPath.row]; // here you access elements in arrray which is stored in names dictionary for usernames[indexPath.section] key

return cell
}

How to create alphabetic sections in TableView with header from MutableArray using swift 3

In

for crime in marrCrimesNames {
crimeFirstLetter = crimeName.characters.first! as AnyObject
print(crimeFirstLetter)
}

You're not actually using the crime variable
Instead you're using only crimeName that's why you're getting "A" all the time.

Try instead

for crime in marrCrimesNames {
crimeFirstLetter = crime.Name.characters.first! as AnyObject
print(crimeFirstLetter)
}

Now to create a dictionary like this:

let dict = ["A" : ["Aname1", "Aname2", "Aname3"], "B" : ["Bname1", "Bname2", "Bname3"]]

from an array like this:

let array = ["Aname1", "Aname2", "Aname3", "Bname1", "Bname2", "Bname3"]

You can use this code:

let dict = ["A" : ["Aname1", "Aname2", "Aname3"], "B" : ["Bname1", "Bname2", "Bname3"]]

let characters = Array(Set(array.flatMap({ $0.characters.first })))

var result = [String: [String]]()

for character in characters.map({ String($0) }) {
result[character] = array.filter({ $0.hasPrefix(character) })
}

print(result) // output: ["B": ["Bname1", "Bname2", "Bname3"], "A": ["Aname1", "Aname2", "Aname3"]]

How to make alphabetically section headers in table view with a mutable data source

I would change the way you store your contacts to a dictonary with the initial letters as keys and put the names that correspond to that initial letter into a subarray:

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

I simplified the way of the contacts here (in form of strings), but you get the concept.

I would also save the section number of the letter in a seperate array like this:

letters = ["A", "C"]

Keep the array sorted and organized, so check after each insertion/deletion/update. This is not part of the table view implementation. I would make the Viewcontroller a delegate of the phonebook, so you can fire an update-like method from the phonebook to update the table.

How to get the data for the data source:

the number of sections:

letters.count

the section title for section at index i is

letters[i]

the number of cells in a section i is

contacts[letters[i]].count

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

contacts[letters[i]][c]

Feel free to ask further questions if anything is still not clear.

UPDATE - How to generate the arrays:

I don't require the data to be sorted, if you pass it already sorted, you can delete the sorting 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 in playground and got the following outputs for

letters:

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

contacts:

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

How do you sort data in a tableView alphabetically by section using a custom model class?

You are doing it the wrong way. You are not using your data to generate your index.

Let's consider you have an array of your data var name: [Name]

  1. Define the section into which every Name belongs:
extension Name {
var titleFirstLetter: String {
return String(self.nameTitle[self.nameTitle.startIndex]).uppercased()
}
}

  1. Generate the index from your data
// all the first letters in your data
let firstLetters = names.map { $0.titleFirstLetter }
// some letters appear multiple times, let's remove duplicates
let uniqueFirstLetters = Array(Set(firstLetters))
// sort them
// this is your index
let sortedFirstLetters = uniqueFirstLetters.sorted()

  1. Generate sections
let sections: [[Name]] = sortedFirstLetters.map { firstLetter in
return names
.filter { $0.titleFirstLetter == firstLetter } // only names with the same first letter in title
.sorted { $0.nameTitle < $1.nameTitle } // sort them
}

  1. Use them
func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
return sortedFirstLetters[section]
}

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

func numberOfSections(in tableView: UITableView) -> Int {
return sections.count // or sortedFirstLetters.count
}

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

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let name = sections[indexPath.section][indexPath.row]
...
}

Edit - complete example:

class Name {
let nameTitle: String
let nameDetail: String

init(nameTitle: String, nameDetail: String) {
self.nameTitle = nameTitle
self.nameDetail = nameDetail
}

var titleFirstLetter: String {
return String(self.nameTitle[self.nameTitle.startIndex]).uppercased()
}
}

class ViewController : UIViewController, UITableViewDelegate, UITableViewDataSource {
@IBOutlet weak var tableView: UITableView?

var names: [Name] = []

var sortedFirstLetters: [String] = []
var sections: [[Name]] = [[]]

override func viewDidLoad() {
super.viewDidLoad()

let cell001 = Name(nameTitle: "Acker", nameDetail: "Details for Acker are listed here.")
names.append (cell001)

let cell002 = Name(nameTitle: "Baker", nameDetail: "Details for Baker are listed here.")
names.append (cell002)

let cell003 = Name(nameTitle: "Caker" , nameDetail: "Details for Caker are listed here.")
names.append (cell003)

let cell004 = Name(nameTitle: "Dacker", nameDetail: "Details for Dacker are listed here.")
names.append (cell004)

let cell005 = Name(nameTitle: "Ecker", nameDetail: "Details for Ecker are listed here.")
names.append (cell005)

let cell006 = Name(nameTitle: "Facker", nameDetail: "Details for Facker are listed here.")
names.append (cell006)

let firstLetters = names.map { $0.titleFirstLetter }
let uniqueFirstLetters = Array(Set(firstLetters))

sortedFirstLetters = uniqueFirstLetters.sorted()
sections = sortedFirstLetters.map { firstLetter in
return names
.filter { $0.titleFirstLetter == firstLetter }
.sorted { $0.nameTitle < $1.nameTitle }
}
}

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

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

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

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

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let name = sections[indexPath.section][indexPath.row]

let cell = UITableViewCell(style: .subtitle, reuseIdentifier: nil)
cell.textLabel?.text = name.nameTitle
cell.detailTextLabel?.text = name.nameDetail

return cell
}
}

example screenshot

Swiftyjson - JSON to table view with alphabetical sections

Just found my way. Answer below.

var sections : [(index: Int, length :Int, title: String)] = Array()
var contactsSorted: [JSON] = [JSON]()

// Delegate from my contact protocol
func didReceiveContacts(contacts: JSON){

var index = 0

for (key,subJson):(String, JSON) in contacts {

let title = "\(key)"

let newSection = (index: index, length: subJson.count, title: title)

sections.append(newSection)

contactsSorted.append(subJson)

index += 1
}
// EDIT:Sort the sections by title to retrieve the alphabetical order
sections.sortInPlace({ $0.title < $1.title })

self.tableView.reloadData()
}

// tableView delegate methods

func numberOfSectionsInTableView(tableView: UITableView) -> Int {

return sections.count

}

func tableView(tableView: UITableView, titleForHeaderInSection section: Int) -> String? {

return sections[section].title

}

func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {

return sections[section].length

}

func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {

let cell = self.tableView.dequeueReusableCellWithIdentifier("contactCell")! as! ContactTableViewCell

cell.nameLabel.text = contactsSorted[sections[indexPath.section].index].array![indexPath.row]["firstName"].string! + " " + contactsSorted[sections[indexPath.section].index].array![indexPath.row]["lastName"].string!

}

how to arrange tableview cells into sections alphabetically with custom header cell?

Keep in mind that UITableView uses its datasource to know which information should appear on the screen. It seems like you already have a datasource list, so you just need to sort this list and the UITableViewDataSource will iterate over it. Do something like this:


func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "CartCell", for: indexPath) as! CartCell

let brandSource = Tray.currentCart.cartItems[indexPath.section].sorted{$0.brand.lowercased() < $1.brand.lowercased()}
let cart = brandSource[indexPath.row]
cell.configure(withItems: cart)

return cell
}

It's a good thing to improve your objects structures a little bit better or soon you will lose control of your app.



Related Topics



Leave a reply



Submit