【问题标题】:How to sort a string array in swift by number and letter values?如何按数字和字母值快速对字符串数组进行排序?
【发布时间】:2023-03-27 20:45:01
【问题描述】:

我正在尝试对这样列出的数组进行排序:

let array = ["02:00 AM", "01:00 AM", "01:00 PM", "01:01 AM", "01:01 PM", "03:00 AM"]

我可以多次在我的 userDefaults 中添加/更新提醒,但我希望它不仅按时间排序,而且按 AM/PM 值排序。这样数组看起来像这样:

["01:00 AM", "01:01 AM", "02:00 AM", "03:00 AM", "01:00 PM","01:01 PM"]

我该怎么做?在数组上使用.sort() 不起作用,因为它只会按时间排序,但我特别希望 AM 字符串在 PM 字符串之前。我将数组作为字符串,因为我认为它会更容易,但我发现这可能不是最好的方法。

【问题讨论】:

  • 一种可能的解决方案是将原始数组拆分为两个数组,arrayAM 和 arrayPM,然后按照您想要的任何顺序对它们进行排序,然后将它们合并为一个数组。
  • 考虑到夏令时问题,您应该使用真实日期而不是字符串。它还允许您对它们进行排序,因为Date 符合Comparable 协议。

标签: ios arrays swift xcode


【解决方案1】:

基于@nighttalker 的答案,您可以使用sorted(by: <) 在一行中得到它。

那么代码是:

let array = ["02:00 AM", "01:00 AM", "01:00 PM", "01:01 AM", "01:01 PM", "03:00 AM"]
let sortedArray = array.filter { $0.contains("AM") }.sorted(by: <) + array.filter { $0.contains("PM") }.sorted(by: <)

但正如 Arkku 所说,您可能应该使用 Date 类型并使其符合 Comparable。

(我还不能评论,所以必须这样提交)

【讨论】:

    【解决方案2】:

    按 12 和 AM 过滤,然后排序。按 12 和 PM 过滤,然后排序。然后加入 2 个数组。

    let array = ["12:00 AM", "12:02 PM", "02:00 AM", "01:00 AM", "01:00 PM", "01:01 AM", "01:01 PM", "03:00 AM"]
    

    我们需要考虑 #12 会影响排序。所以需要用12过滤掉所有的时间,排序,放在前面。

    let amc = array.filter { $0.hasPrefix("12") }.filter { $0.hasSuffix("AM") }.sorted(by: <) + array.filter { !$0.hasPrefix("12") }.filter { $0.hasSuffix("AM") }.sorted(by: <)
    let pmc = array.filter { $0.hasPrefix("12") }.filter { $0.hasSuffix("PM") }.sorted(by: <) + array.filter { !$0.hasPrefix("12") }.filter { $0.hasSuffix("PM") }.sorted(by: <)
    let comb = amc + pmc
    print(comb) // prints ["12:00 AM", "01:00 AM", "01:01 AM", "02:00 AM", "03:00 AM", "12:02 PM", "01:00 PM", "01:01 PM"]
    

    通过这个练习,很明显使用Date 是最好的方法。

    【讨论】:

    • 关于上午 12 点与下午 12 点比较的好点 - 我习惯了 24 小时制,所以我没有意识到 12:01 PM 真的是 00:01 PM 用于排序. (我认为这证明使用 Date 对象等而不是字符串会更好。)无论如何,您当前对 12 AM/PM 的实现是有缺陷的:分钟也可能是 12,这与 @987654325 匹配@。应该是.hasPrefix("12")。此外,12: 案例的处理也被破坏了:考虑 12:1512:30 是如何相对于彼此排序的。
    【解决方案3】:
    let morningTimes = arrayOfTimes.filter{$0.contains("AM") && !$0.contains("12:")}.sorted()
    let dayTimes = arrayOfTimes.filter{$0.contains("12:") && $0.contains("AM")}.sorted() + morningTimes
    let nightTimes = arrayOfTimes.filter{$0.contains("PM") && !$0.contains("12:")}.sorted()
    let allTimes = dayTimes + arrayOfTimes.filter{$0.contains("12:") && $0.contains("PM")}.sorted() + nightTimes
    

    【讨论】:

    • 尝试使用["02:00 AM", "01:12 AM", "01:00 PM", "01:01 AM", "01:01 PM", "03:00 AM", "12:15 AM", "12:30 AM", "12:01 PM", "12:30 PM" ] 作为输入。 =)
    • 感谢@Arkku 的建设性批评对我改进解决方案很有帮助
    【解决方案4】:

    您可以传递sort 一个块并在那里实现比较逻辑,例如:

    var array = ["02:00 AM", "01:12 AM", "01:00 PM", "01:01 AM", "01:01 PM", "03:00 AM", "12:15 AM", "12:30 AM", "12:01 PM", "12:30 PM" ]
    array.sort { s1, s2 in
        let isAM1 = s1.contains("AM")
        let isAM2 = s2.contains("AM")
        return isAM1 && !isAM2 || ((isAM1 == isAM2) && s1 < s2)
    }
    

    当且仅当第一个参数要排在第二个之前,比较块应该返回true。这是在这里实现的,第一个是 AM,第二个是 PM,或者两者都是相同的 AM/PM,而第一个有更早的时间。

    P。 S. 您可能会考虑首先使用Date 对象而不是字符串(您始终可以根据需要将它们格式化回字符串)。

    编辑:如果您的字符串使用“12:00 PM”是中午和“12:00 AM”是午夜的约定,则上述时间将错误地排序。您可以通过测试s1.hasPrefix("12:") 并反转“is AM”状态来解决这个问题:

    if s1.hasPrefix("12:") {
        isAM1 = !isAM1
    }
    if s2.hasPrefix("12:") {
        isAM2 = !isAM2
    }
    

    即使这种方法将12:59 AM 排序在最后而不是在01:00 AM 之前进行排序——如果这是一个问题,您可以微调比较。但是,我认为仅此复杂性就足以有理由使用Date 对象(或您自己的Comparable 时间持有者)而不是字符串。假设您不愿意切换到 24 小时制。 =)

    【讨论】:

    • 如果您要解释问题所在,投反对票会更有建设性。
    猜你喜欢
    • 2016-07-23
    • 2011-03-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-12-19
    • 2021-07-13
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多