假设有一个数组:
var array = ["5C", "4D", "2H", "13S", "4C", "5H"]
如何将这个数组排序,使得新的数组按照最后一个字符的字母顺序排列,之前的数字按照数值大小排序,例如:
["4C", "5C", "4D", "2H", "5H", "13S"]
我对编程语法只有很基本的了解。我已经搜索过如何使用 .sorted 函数和 .ascendingOrder 来进行数字排序,但是我找不到同时可以按照字母和数字排序的解决方案。
你需要编写自己的比较器,这在Swift中非常方便。
如果最后一个字符相同,则按数字顺序对字符串进行排序,否则按最后一个字符排序。
let array = ["5C", "4D", "2H", "13S", "4C", "5H"]
let sortedArray = array.sorted { (str1, str2) -> Bool in
if str1.suffix(1) == str2.suffix(1) {
return str1.dropLast().localizedStandardCompare(str2.dropLast()) == .orderedAscending
} else {
return str1.suffix(1) < str2.suffix(1)
}
}
// ["4C", "5C", "4D", "2H", "5H", "13S"]
我的回答展示了如何使用 sorted()
对字符串数组进行“数字”排序。但这并不完全符合提问者的要求。
对于提问者:你应该接受 vadian 的答案,他的是第一个正确的答案。
然而,在我的答案中我花了一些时间解释了 Swift 闭包语法,因此我还是会保留这个答案。
你可以使用数组方法 sorted()
,它需要一个闭包作为参数,比较对象对并返回 true 如果第一个元素应该排在前面。
然后,你可以使用 NSString 方法 compare(options:)
进行“数字”字符串比较,其中数字序列在字符串内被视为数字。
下面是一个可以工作的代码片段,将对你的数组进行排序:
var array = ["5C", "4D", "2H", "13S", "4C", "5H"]
let sorted = array.sorted (by: { (first: String, second: String) -> Bool in
return first.compare(second, options: .numeric) == .orderedAscending
})
sorted()
函数是一个高阶函数,也就是一个接收另一个函数作为参数的函数。对于一组字符串来说,该函数需要接收两个字符串并返回一个布尔值。它实际上接收的是一个闭包而不是一个函数,其中闭包是一个“匿名函数”(没有名称的函数)。
根据vadian的代码修改我的片段,代码如下:
var array = ["5C", "4D", "2H", "13S", "4C", "5H"]
let sorted = array.sorted (by: { (first: String, second: String) -> Bool in
if first.suffix(1) == second.suffix(1) {
return first.dropLast.compare(second, options: .numeric) == .orderedAscending
} else {
return first.suffix(1) < second.suffix(1)
}
})
您可以使用几个快捷方式重写上面的代码:
使用 "尾随闭包",您可以跳过包含闭包作为参数的()
,只需在函数名称后用花括号提供闭包即可。
您可以省略闭包的参数和返回类型声明,并跳过返回语句:
let sorted = array.sorted { $0.compare($1, options: .numeric) == .orderedAscending }
对于像vadian的那样能够给出正确答案的更复杂的代码,我建议不要使用这种位置参数。使用像first
和second
这样的本地变量可以使代码更易于阅读。
我建议仔细研究苹果的Swift iBooks中关于闭包的章节,直到您理解闭包可以表达的各种方式及其不同的快捷语法为止。起初很困惑,而使用闭包是使用Swift的基础。
let sorted = array.sorted { $0.compare($1, options: .numeric) == .orderedAscending }
我认为这是正确的... 暂时没有代码。 - xTwisteDx["2H", "4C", "4D", "5C", "5H", "13S"]
,但这不是 OP 寻找的。 - vadianstruct Thing: Equatable { // FIXME: Name me something descriptive
let number: Int // FIXME: Name me something descriptive
let letter: Character // FIXME: Name me something descriptive
static func parse(from string: String) -> Thing? {
let numberSegment = string.prefix(while: { $0.isNumber })
guard !numberSegment.isEmpty,
let number = Int(numberSegment) else { return nil }
let letterSegement = string.drop(while: { $0.isNumber })
guard letterSegement.count == 1,
let letter = letterSegement.first else { return nil }
return Thing(number: number, letter: letter)
}
}
然后,您可以遵守Comparable
,通过定义比较运算符<
来定义您想要排序的方式:
extension Thing: Comparable {
static func < (lhs: Thing, rhs: Thing) -> Bool {
return (lhs.letter, lhs.number) < (rhs.letter, rhs.number)
}
}
从那里开始,只需要将所有字符串解析为Thing
,并对它们进行排序:
let array = ["5C", "4D", "2H", "13S", "4C", "5H"]
let things = array.map { Thing.parse(from: $0)! }
print("Before sorting:")
things.forEach { print("\t\($0)") }
let sortedThings = things.sorted()
print("\nAfter sorting:")
sortedThings.forEach { print("\t\($0)") }
输出:
Before sorting:
Thing(number: 5, letter: "C")
Thing(number: 4, letter: "D")
Thing(number: 2, letter: "H")
Thing(number: 13, letter: "S")
Thing(number: 4, letter: "C")
Thing(number: 5, letter: "H")
After sorting:
Thing(number: 4, letter: "C")
Thing(number: 5, letter: "C")
Thing(number: 4, letter: "D")
Thing(number: 2, letter: "H")
Thing(number: 5, letter: "H")
Thing(number: 13, letter: "S")
Card
(而不仅仅是一个通用的String
),因此Swift编译器可以强制执行您不能提供像“Hello World!”这样的无意义字符串。是的,您应该创建一个struct Card
,其中包含rank: Rank
和suit: Suite
,其中Rank
和Suite
都是枚举类型,列举了13个等级(Ace,2-10,J,Q,K)和4个套房。请参见https://dev59.com/KGAf5IYBdhLWcg3w9Wmu - Alexandervar array = ["5C", "4D", "2H", "13S", "4C", "5H"]
array = array.sorted { $0.numbersValues < $1.numbersValues }
let str = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
var newArrray: [String] = []
for letter in str {
for value in array {
if value.lettersValues.hasPrefix(String(letter)) {
newArrray.append(value)
}
}
}
不要忘记在你的项目中包含这些辅助方法
extension String {
var lettersValues: String {
return self.components(separatedBy: CharacterSet.decimalDigits).joined()
}
var numbersValues: String {
return self.filter { "0"..."9" ~= $0 }
}
}