Swift-需要对星期几的字符串进行排序

时间:2018-11-03 20:52:43

标签: arrays swift sorting

雨燕4

我有一个数组,其中将包含星期几中的随机文本。例如

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

我希望能够对它们进行排序:星期天,星期一,星期二,等等...

我不确定这是否是正确的方法,但是我尝试过。.

     let dateFormatter = DateFormatter()

    for element in daysOfWeek {

        print(dateFormatter.weekdaySymbols[element])
    }

哪个抛出错误:

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

我对Xcode和Swift还是陌生的

这是正确的方法吗?如果是这样,我该如何解决错误?

如果这不是正确的方法,那是什么? 感谢您的帮助

5 个答案:

答案 0 :(得分:5)

您可以创建像这样的字典,该字典将每个字符串与一个数值对应:

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

然后您可以按此排序:

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

这将在非工作日字符串的末尾排序。

还要注意,世界不同地区的一周开始时间不同。他们可能会以不同的方式订购东西。

答案 1 :(得分:1)

这是这样做的方法:

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

这样,将根据当前的语言环境和系统设置自动设置日期名称和一周中的第一天。例如:

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

要对某些日期名称进行排序:

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"]

为简洁起见,我在这里用力包裹。您可以使用以下命令检查daysOfWeek中的所有字符串是否有效:

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")
}

邓肯先生所建议的那样,为了使上述解决方案更快,这是另一种方法:

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"]

使用字符串作为日期名称标识符容易出错。一种更安全的方法是使用枚举:

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"]

答案 2 :(得分:1)

我的解决方案是@sweeper解决方案的一种变体:

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)")

我的代码构建了一个包含工作日名称及其索引值的字典,例如Sweeper的答案。 Carpsen的使用firstIndex(of:)的方法可以工作,但是会更慢,并且对于较大的字符串数组可能会慢很多。 我正在使用当前日历中的工作日符号,该符号将位于用户的区域设置/语言中。如果您想将星期几名称强制设置为特定的语言/语言环境,则可以使用为该语言/语言环境创建的DateFormatter,如Carpsen的答案。

请注意,如果输入的工作日名称字符串的大小写不可预测,那么您可能需要稍稍更改上面的代码,以降低工作日名称字典的大小写,并以小写形式排列要排序的字符串那个星期几的大小写仍然匹配。


编辑:

我编写了一个测试命令行工具,该工具同时使用了基于数组的项目匹配(根据@ Carpsen90的第一个解决方案)和基于my / Sweeper的基于字典的匹配,发现基于数组的版本大约需要5倍的时间工作日名称的1,000,000元素数组。实话实说,对1M件商品的价格是其5倍还不错。这表明这两种方法具有相同的时间复杂度。

但是,当我在编译器中打开“针对速度进行优化”时,基于字典的方法则需要花费大约2.8倍的时间!

下面是所有测试代码:

//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")
}

关闭优化功能(调试默认设置),结果是:

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

但是选择“针对速度进行优化”后,结果会大不相同:

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

这真是令人惊讶,我也不知道该怎么解释。

编辑#2:

好,我知道了。实际上,我们匹配的键的数组/字典中只有7个可能的值会使结果偏斜。

我进行了另一项测试,而不是一周中的几天,而是将拼写数字从“一个”排序为“一千”。在这种情况下,基于字典的方法比我预期的要快很多:< / p>

针对时间性能进行了优化,并使用了1000个唯一的单词:

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

(处理1000个唯一的单词,基于数组的方法太慢了,无法排序1,000,000个随机单词。在第二组测试中,我不得不将随机单词的数量降低到100,000个。)

答案 3 :(得分:1)

这里的解决方案不需要创建工作日及其索引的字典。

func sortWeekDays(_ weekDays: [String]) -> [String]? {
    guard let correctOrder = DateFormatter().weekdaySymbols else {
        return nil
    }
    let result = weekDays.sorted {
        guard let firstItemIndex = correctOrder.firstIndex(of: $0),
            let secondItemIndex = correctOrder.firstIndex(of: $1) else {
                return false
        }
        return firstItemIndex < secondItemIndex
    }
    return result
}

答案 4 :(得分:0)

首先将数组转换为String并检查
选定的日期= [“星期五”,“星期四”,“星期一”]
让stringRepresentation = selectedDays.joined(separator:“,”)

    var sequenceDays = [String]()
    if stringRepresentation.contains("Monday") {
        sequenceDays.append("Monday")
    }
    if stringRepresentation.contains("Tuesday") {
        sequenceDays.append("Tuesday")
    }
    if stringRepresentation.contains("Wednesday") {
        sequenceDays.append("Wednesday")
    }
    if stringRepresentation.contains("Thursday") {
        sequenceDays.append("Thrusday")
    }
    if stringRepresentation.contains("Friday") {
        sequenceDays.append("Friday")
    }
    if stringRepresentation.contains("Saturday") {
        sequenceDays.append("Saturday")
    }
    if stringRepresentation.contains("Sunday") {
        sequenceDays.append("Sunday")
    }

    print(sequenceDays)//["Monday","Thursday","Friday"]

// let Days = sequenceDays.joined(分隔符:“,”) 打印(天) let parsedDays = Days.replacingOccurrences(of:“ day”,其中:“”) 打印(parsedDays)