I have Contact model and I want to sort by [firstLetter, fullName] into [section,row] for UITableView in this way "FAVORITES" at startIndex, "#" at endIndex and between them are sorted letters.
For example: ["A", "C", "E", "#", "FAVORITES"] into ["FAVORITES", "A", "C", "E", "#"]
This is model
class Contact: Object {
dynamic var fullName = ""
dynamic var firstLetter = ""
}
Here's UITableViewController, where I sort data
class ContactsController: UITableViewController {
// some code
var contacts = try! Realm().objects(Contact.self).filter("isDeleted == false").sorted(by: ["firstLetter","fullName"])
var sections: [String] {
return Set(contacts.value(forKeyPath: "firstLetter") as![String]).sorted()
}
override func viewDidLoad() {
super.viewDidLoad()
setUI()
}
// another code
}
Edit #1
Sorry, I forgot to say that "#" contains contacts where fullName begins with special characters
Answer for my question
var sections: [String] {
return Set(contacts.value(forKeyPath: "firstLetter") as![String]).sorted {
//Favourites sorts before all else
if $0 == "FAVORITES" { return true }
if $1 == "FAVORITES" { return false }
// Symbols sort after all else
if $0 == "#" { return false }
if $1 == "#" { return true }
return $0 < $1
}
}
Here is how I would do this. I had to change the data structure for testing purposes, but you can change it back to a class that inherits from Object.
public extension Sequence {
public typealias Element = Iterator.Element
public typealias Group = [Element]
public func group<Key: Hashable>(by deriveKey: (Element) -> Key) -> [Key: Group] {
var groups = [Key: Group]()
for element in self {
let key = deriveKey(element)
if var existingArray = groups[key] { // Group already exists for this key
groups[key] = nil //performance optimisation to prevent CoW
existingArray.append(element)
groups[key] = existingArray
}
else {
groups[key] = [element] // Create new group
}
}
return groups
}
}
struct Contact: CustomStringConvertible {
let fullName: String
let isFavourte: Bool
var firstLetter: Character {
return fullName.characters.first!
}
var containsSpecialLetters: Bool {
return false // implement me
}
init(_ fullName: String, _ isFavourte: Bool) {
self.fullName = fullName
self.isFavourte = isFavourte
}
var description: String { return fullName }
}
let contacts = [
Contact("Alice", false),
Contact("Alex", false),
Contact("Bob", true),
Contact("Bill", false),
Contact("Cory", false),
Contact("Casey", true),
Contact("#åœ∑´ß", false),
Contact("D", false),
Contact("E", false),
Contact("F", false),
Contact("G", false),
Contact("H", false),
]
let sections = contacts.group{ contact -> String in
switch contact {
case _ where contact.isFavourte: return "Favourites"
case _ where contact.containsSpecialLetters: return "#"
case _: return String(contact.firstLetter)
}
}
let sectionHeaders = sections.keys.sorted {
//Favourites sorts before all else
if $0 == "Favourites" { return true }
if $1 == "Favourites" { return false }
// Symbols sort after all else
if $0 == "#" { return false }
if $1 == "#" { return true }
return $0 < $1
}
for (sectionHeader, sectionContacts) in sectionHeaders.map({($0, sections[$0]!)}) {
print("===== \(sectionHeader) =====")
sectionContacts.forEach{ print($0) }
}
Output:
===== Favourites =====
Bob
Casey
===== A =====
Alice
Alex
===== B =====
Bill
===== C =====
Cory
===== D =====
D
===== E =====
E
===== F =====
F
===== G =====
G
===== H =====
H
===== # =====
åœ∑´ß
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With