Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Swift - need to sort an array of string days of week

Swift 4

I have an array that will have random days of the week text in it. For example

var daysOfWeek: [String] = [] // ["Tuesday", "Thursday" , "Sunday", "Friday"]

I want to be able to sort them like: Sunday, Monday, Tuesday, ect...

Im not sure if this is the right approach, but I tried this..

     let dateFormatter = DateFormatter()

    for element in daysOfWeek {

        print(dateFormatter.weekdaySymbols[element])
    }

Which throws an error:

value of optional type '[String]?' must be unwrapped to refer to member 'subscript' of wrapped base type

Im fairly new to Xcode and Swift

Is this the right way to do it? if so, how can I fix the error?

If this isn't the right way to do it, then what is? I appreciate any help

like image 432
steller Avatar asked Oct 27 '25 13:10

steller


2 Answers

You can create a dictionary like this, that corresponds each string to a numerical value:

let weekDayNumbers = [
    "Sunday": 0,
    "Monday": 1,
    "Tuesday": 2,
    "Wednesday": 3,
    "Thursday": 4,
    "Friday": 5,
    "Saturday": 6,
]

And then you can just sort by this:

weekdays.sort(by: { (weekDayNumbers[$0] ?? 7) < (weekDayNumbers[$1] ?? 7) })

This will order non-weekday strings at the end.

Also note that different areas of the world have a different start of week. They might order things differently.

like image 173
Sweeper Avatar answered Oct 30 '25 07:10

Sweeper


Here is the way to do it:

let week = DateFormatter().weekdaySymbols!
print(week)  //["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"]

This way, the day names and the first day of the week will be set automatically based on the current locale and system settings. For example:

let formatter = DateFormatter()
formatter.locale = Locale(identifier: "fr-FR")
let week = formatter.weekdaySymbols!
print(week)  //["dimanche", "lundi", "mardi", "mercredi", "jeudi", "vendredi", "samedi"]

To sort an array of some day names:

let week = DateFormatter().weekdaySymbols!
var daysOfWeek: [String] = ["Tuesday", "Thursday" , "Sunday", "Friday"]
daysOfWeek.sort { week.firstIndex(of: $0)! < week.firstIndex(of: $1)!}
print(daysOfWeek) //["Sunday", "Tuesday", "Thursday", "Friday"]

I am force-unwrapping here just for brevity. You could check that all strings in daysOfWeek are valid using:

var daysOfWeek: [String] = ["Tuesday", "Thursday" , "Sunday", "Friday"]
let week = DateFormatter().weekdaySymbols!
guard Set(daysOfWeek).isSubset(of: week) else {
    fatalError("The elements of the array must all be day names with the first letter capitalized")
}

To make the above solution quicker, as suggested by Mr Duncan, here is an alternative approach:

let week = DateFormatter().weekdaySymbols!
var dayDictionary: [String: Int] = [:]
for i in 0...6 {
    dayDictionary[week[i]] = i
}
var daysOfWeek: [String] = ["Tuesday", "Thursday" , "Sunday", "Friday"]
daysOfWeek.sort { (dayDictionary[$0] ?? 7) < (dayDictionary[$1] ?? 7)}
print(daysOfWeek) //["Sunday", "Tuesday", "Thursday", "Friday"]

Using strings as day name identifiers is prone to error. A safer approach uses enums:

enum WeekDay: String {
    case first      = "Sunday"
    case second     = "Monday"
    case third      = "Tuesday"
    case fourth     = "Wednesday"
    case fifth      = "Thursday"
    case sixth      = "Friday"
    case seventh    = "Saturday"
}

let week: [WeekDay] = [.first, .second, .third, .fourth, .fifth, .sixth, .seventh]
var dayDictionary: [WeekDay : Int] = [:]
for i in 0...6 {
    dayDictionary[week[i]] = i
}
var daysOfWeek: [WeekDay] = [.third, .fifth , .first, .sixth]
daysOfWeek.sort { (dayDictionary[$0] ?? 7) < (dayDictionary[$1] ?? 7)}
print(daysOfWeek.map {$0.rawValue}) //["Sunday", "Tuesday", "Thursday", "Friday"]
like image 44
ielyamani Avatar answered Oct 30 '25 06:10

ielyamani