简体   繁体   English

如何按数字和字母值对 swift 中的字符串数组进行排序?

[英]How to sort a string array in swift by number and letter values?

I'm trying to sort an array that is listed as such:我正在尝试对这样列出的数组进行排序:

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

It's a series of times that I can add/update in my userDefaults for reminders, however I want it sorted not only by the time but by the AM/PM value.这是我可以在我的 userDefaults 中添加/更新以进行提醒的一系列时间,但是我希望它不仅按时间排序,而且按 AM/PM 值排序。 that way the array looks like this:这样数组看起来像这样:

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

How can I do this?我怎样才能做到这一点? Using .sort() on the array doesn't work since that will just sort by time, but I specifically want the AM strings before the PM strings.在数组上使用.sort()不起作用,因为它只会按时间排序,但我特别希望 AM 字符串在 PM 字符串之前。 I have the array as a String since I thought it would be easier, but I'm seeing that this may not be be best way about it.我将数组作为字符串,因为我认为它会更容易,但我看到这可能不是最好的方法。

Filter by 12 & AM, then sort.按 12 & AM 过滤,然后排序。 Filter by 12 & PM, then sort.按 12 和 PM 过滤,然后排序。 Then join the 2 arrays.然后加入2个arrays。

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

We need to consider that the #12 will impact sorting.我们需要考虑 #12 会影响排序。 So you need to filter out all times with 12, sort them, and place them in front.所以需要用 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"]

With this exercise, it's clear that using Date is the best approach.通过这个练习,很明显使用Date是最好的方法。

Building on @nighttalker 's answer you could get it in one line using sorted(by: <) .基于@nighttalker 的答案,您可以使用sorted(by: <)在一行中得到它。

Then the code would be:那么代码将是:

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

but as Arkku said you probably should use the Date type and make it conform to Comparable.但正如 Arkku 所说,您可能应该使用 Date 类型并使其符合 Comparable。

(I am not yet able to comment, so had to submit it this way) (我还不能评论,所以必须这样提交)

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

You can pass sort a block and implement the comparison logic there, eg:您可以传递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)
}

The comparison block should return true if and only if the first argument is to be sorted before the second.当且仅当第一个参数要排在第二个之前,比较块才应该返回true This is implemented here such that either the first is AM and the second is PM, or both are the same AM/PM and the first has an earlier time.这是在这里实现的,第一个是 AM,第二个是 PM,或者两者都是相同的 AM/PM,而第一个具有更早的时间。

PS You might consider using Date objects instead of strings in the first place (you can always format them back into strings as needed). PS您可能首先考虑使用Date对象而不是字符串(您始终可以根据需要将它们格式化回字符串)。

Edit : If your strings use the convention where "12:00 PM" is noon and "12:00 AM" is midnight, such times would be sorted incorrectly by the above.编辑:如果您的字符串使用“12:00 PM”为中午且“12:00 AM”为午夜的约定,则上述时间将错误地排序。 You can sort of fix that by testing for s1.hasPrefix("12:") and inverting the "is AM" status:您可以通过测试s1.hasPrefix("12:")并反转“is AM”状态来解决这个问题:

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

Even this approach sorts 12:59 AM last instead of right before 01:00 AM – you can fine-tune the comparison if this is an issue.即使这种方法最后排序是在上午12:59 AM ,而不是在01:00 AM之前进行排序——如果这是一个问题,您可以微调比较。 However, I think this complexity alone is sufficient reason to use Date objects (or your own Comparable time holders) rather than strings.但是,我认为仅凭这种复杂性就足以有理由使用Date对象(或您自己的Comparable时间持有者)而不是字符串。 Assuming you are unwilling to switch to a 24-hour clock.假设您不愿意切换到 24 小时制。 =) =)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM