Search code examples
swiftnsarray

Add address book like letters in array of names


I'm trying to take an array of people (simplified with just a first name for now) and not only sort it, but also add the first letter in front of all people starting with this letter.

Basically this: ["Daniel", "Michael", "Lisa", "Lena"] should become this: ["D", "Daniel", "L", "Lena", "Lisa", "M", "Michael"]

I have something working in a playground, but to me this looks ugly as hell and no idea about performance if people get in the thousands or more.

//: Playground - noun: a place where people can play

import Cocoa

var previousName: String?

let people = ["Martin", "Michael", "Lisa", "Lena", "Dirk"]
var peopleWithLetters: [String] = []

people.sorted { $0.localizedCaseInsensitiveCompare($1) == ComparisonResult.orderedAscending }.forEach {
    if $0.uppercased().characters.first! != previousName?.uppercased().characters.first! {
        peopleWithLetters.append("\($0.uppercased().characters.first!)")
    }
    previousName = $0
    peopleWithLetters.append($0)
}

Any idea how to streamline or follow best practices would be highly appreciated.


Solution

  • This is a perfect usecase where functional programming shines.

    • Map array of names to array of first letters
    • Use a set to remove duplicates
    • Combine letters with names
    • Sort the array

    Here is the code:

    //: Playground - noun: a place where people can play
    
    func addSections(in words: [String]) -> [String] {
        let sections = Set(words.map { String($0[$0.startIndex]) })
        let wordsWithSections = words + sections
        return wordsWithSections.sorted { $0 < $1 }
    }
    
    let names = ["Daniel", "Michael", "Lisa", "Lena"]
    addSections(in: names)
    

    Although if you plan on using this array to feed a tableView (sections/rows) you would be better off with a dictionary like you mentioned in your comment.