Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Swift Set Array custom sort

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
        }
    }
like image 994
Damir Shakenov Avatar asked May 29 '26 16:05

Damir Shakenov


1 Answers

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

===== # =====

åœ∑´ß

like image 120
Alexander Avatar answered Jun 01 '26 07:06

Alexander



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!