繁体   English   中英

如何在 Swift 中按数字和字母顺序对数组进行排序

[英]How to sort an array both numerically and alphabetically in Swift

假设我有一个数组:

var array = ["5C", "4D", "2H", "13S", "4C", "5H"]

我如何能够对这个数组进行排序,以便新数组的最后一个字符按字母顺序排序,然后以前的数值按数字顺序排序,例如:

["4C", "5C", "4D", "2H", "5H", "13S"]

一般来说,我对编码相对较新,并且对语法有非常基本的掌握。 其他搜索向我展示了如何使用 .sorted function 和 .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()将字符串数组排序为“数字”顺序。 这不是OP所要求的。

致 OP:您应该接受 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
})

The function sorted() is a "higher order function`, or a function that takes another function as a parameter. For an array of strings, that function takes 2 strings, and returns a Bool. It actually takes a closure rather than a function ,其中闭包是“匿名函数”(没有名称的 function。)

调整 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)
    }
})

您可以使用几个快捷方式重写上述内容:

使用“尾随闭包”,您可以跳过包含闭包作为参数的() ,只需在 function 名称后的大括号中提供闭包。

可以跳过闭包的参数和返回类型的声明,也可以跳过return语句:

let sorted = array.sorted { $0.compare($1, options: .numeric) == .orderedAscending }

对于像 vadian 这样给出正确答案的更复杂的代码,我建议不要使用这样的位置参数。 使用像firstsecond这样的局部变量使代码更易于阅读。

我建议仔细研究 Apple 的 Swift iBooks 中关于闭包的章节,直到您了解闭包的各种表达方式及其不同的快捷语法。 一开始会让人困惑,使用闭包是使用 Swift 的基础。

欢迎来到 StackOverflow!

这些数字代表什么? 我将创建一个struct model 那个“东西”(我现在称它为Thing )和 function 可以将String解析为Thing ,如下所示:

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

Output:

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

欢迎来到 StackOverflow!

这是我的解决方案希望它对你有用,我只是先组织数字,然后与字母进行比较以创建一个新数组:

var 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 }
        }
    }

暂无
暂无

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

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