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]
- Define the section into which every
Name
belongs:
extension Name {
var titleFirstLetter: String {
return String(self.nameTitle[self.nameTitle.startIndex]).uppercased()
}
}
- 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()
- 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
}
- 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
}
}
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
iOS 14 Widget Detect System Theme Change
Does Cidetector for Other Barcode Types
Swift: Gradient Splits on Rotation
Add Custom .Colornames to UIcolor Somehow
Didupdateheading Not Called in Swift
Siri Remote's Menu Button Not Exiting Application When UIbutton Is Focused
Osx/Swift: Call a Function When Internet Connection Is Established/Restored
Mkpolyline Broken When Using Type Satelliteflyover
Swift: Change Speed of a Moveto Skaction
How to Use Mtlblitcommandencoder for Copying Interlaced Video Fields into a Mtlbuffer
Audiokit Seems to Receive Only The First Three Numbers of Sysex Midi Messages
Why Does Editing a Textfield Throw a Nsinvalidargumentexception
Uiscrollview Controller Not Scrolling Fully
Social Framework Is Deprecated in iOS11
Encode Struct and Convert to Dictionary [String: Any]
Downloading PDF Using Nsurlsession (Http Post) with Parameters
.Childadded Observer Doesn't Get Called If The Function Is Not Called Explicitly. Swift 4