My solution is a variant of @sweeper's solution:
var inputDaysOfWeek: [String] = ["Tuesday", "Thursday" , "Sunday", "Friday", "Foo", "Bar"]
print("inputDaysOfWeek = \(inputDaysOfWeek)")
//Build a dictionary of days of the week using the current calendar,
//which will use the user's current language
//This step only needs to be done once, at startup.
var weekdaysDict = [String: Int]()
let weekdays = Calendar.current.weekdaySymbols.enumerated()
weekdays.forEach { weekdaysDict[$0.1] = $0.0 }
//-----------------
//If a weekday name doesn't match the array of names, use a value of -1,
//which will cause it to sort at the beginning of the sorted array.
inputDaysOfWeek.sort {weekdaysDict[$0] ?? -1 < weekdaysDict[$1] ?? -1 }
print("sorted inputDaysOfWeek = \(inputDaysOfWeek)")
My code builds a dictionary of weekday names and their index values, like Sweeper's answer. Carpsen's approach of using firstIndex(of:) will work, but it will be slower, and for large arrays of strings might be quite a bit slower.
I'm using the weekday symbols from the current calendar, which will be in the user's locale/language. If you want to force the array of weekday names to a specific language/locale, you could instead use a DateFormatter created for that language/locale, as in Carpsen's answer.
Note that if the upper-lower case value of the input weekday name strings is unpredictable then you might want to change the code above slightly to lowerCase the dictionary of weekday names and also lower-case the array of strings to be sorted so that weekday names with different case still match.
EDIT:
I wrote a test command line tool that uses both array-based matching of items (as per @Carpsen90's first solution) and my/Sweeper's dictionary-based matching, and found that the array-based version takes about 5x as long on a 1,000,000 element array of weekday names. A factor of 5x on 1M items isn't bad, truth be told. That suggests that the two approaches have the same time complexity.
HOWEVER, when I turn on "optimize for speed" in the compiler, however, the dictionary based approach then takes about 2.8x longer!
Below is all the test code:
//Build a dictionary of days of the week using the current calendar,
//which will use the user's current language
var weekdaysDict = [String: Int]()
let weekdays = Calendar.current.weekdaySymbols
let weekdayTuples = weekdays.enumerated()
weekdayTuples.forEach { weekdaysDict[$0.1] = $0.0 }
//--------------- --
func sortWeekDaysUsingDict(array: [String]) -> [String] {
let result = array.sorted { weekdaysDict[$0] ?? -1 < weekdaysDict[$1] ?? -1 }
return result
}
func sortWeekDaysUsingArray(array: [String]) -> [String] {
let result = array.sorted { weekdays.firstIndex(of: $0)! < weekdays.firstIndex(of: $1)! }
return result
}
/*This function times a sorting function
It takes an array to sort, a function name (for logging) and a function pointer to the sort function.
It calculates the amount of time the sort function takes, logs it, and returns it as the function result.
*/
func sortArray(array: [String],
functionName: String,
function: ([String]) -> [String]) -> TimeInterval {
let start = Date().timeIntervalSinceReferenceDate
let _ = function(array)
let elapsed = Date().timeIntervalSinceReferenceDate - start
print("\(functionName) for \(array.count) items took " + String(format: "%.3f", elapsed) + " seconds")
return elapsed
}
//Build a large array of random day-of-week strings:
var randomWeekdayNames = [String]()
for _ in 1 ... 1_000_000 {
randomWeekdayNames.append(weekdays.randomElement()!)
}
let time1 = sortArray(array: randomWeekdayNames,
functionName: "sortWeekDaysUsingDict(array:)",
function: sortWeekDaysUsingDict(array:))
let time2 = sortArray(array: randomWeekdayNames,
functionName: "sortWeekDaysUsingArray(array:)",
function: sortWeekDaysUsingArray(array:))
if time1 > time2 {
print("dict-based sorting took " + String(format:"%0.2f", time1/time2) + "x longer")
} else {
print("array-based sorting took " + String(format:"%0.2f", time2/time1) + "x longer")
}
With optimization turned off (the debug default) The result is:
sortWeekDaysUsingDict(array:) for 1000000 items took 9.976 seconds
sortWeekDaysUsingArray(array:) for 1000000 items took 59.134 seconds
array-based sorting took 5.93x longer
But with "optimize for speed" selected, the results are quite different:
sortWeekDaysUsingDict(array:) for 1000000 items took 3.314 seconds
sortWeekDaysUsingArray(array:) for 1000000 items took 1.160 seconds
dict-based sorting took 2.86x longer
That is quite surprising, and I don't know how to explain it.
EDIT #2:
Ok, I figured it out. The fact there are only 7 possible values in the array/dict of keys we're matching skews the results.
I did another test where instead of days of the week, I was sorting spelled-out numbers from "one" to "one thousand" In that case, the dict-based approach is a LOT faster, as I expected:
Optimized for time performance, and using 1,000 unique words:
sortWeekDaysUsingDict(array:) for 100000 items took 0.520 seconds
sortWeekDaysUsingArray(array:) for 100000 items took 85.162 seconds
array-based sorting took 163.64x longer
(Dealing with 1000 unique words, the array-based approach is too slow with 1,000,000 random words to sort. I had to lower the number of random words to 100,000 for the second set of tests.)