简体   繁体   English

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

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

Say I have an array:假设我有一个数组:

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

How would I be able to sort this array so that the new array would have the last character sorted alphabetically, then the previous numerical values sorted numerically such as:我如何能够对这个数组进行排序,以便新数组的最后一个字符按字母顺序排序,然后以前的数值按数字顺序排序,例如:

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

I am relatively new to coding in general and have a very basic grasp of syntax.一般来说,我对编码相对较新,并且对语法有非常基本的掌握。 Other searches have shown me how to sort numerically using the.sorted function and.ascendingOrder, but I couldn't find a solution that could sort both alphabetically and numerically.其他搜索向我展示了如何使用 .sorted function 和 .ascendingOrder 进行数字排序,但我找不到可以同时按字母和数字排序的解决方案。

You have to write your own comparator which is pretty handy in Swift.您必须编写自己的比较器,这在 Swift 中非常方便。

If the last character is the same sort the string without the last character numerically otherwise sort by the last character如果最后一个字符相同,则对没有最后一个字符的字符串进行数字排序,否则按最后一个字符排序

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

EDIT:编辑:

My answer shows how to use sorted() to sort an array of strings into "numeric" order.我的回答显示了如何使用sorted()将字符串数组排序为“数字”顺序。 It is not quite what the OP asked.这不是OP所要求的。

To the OP: You should accept vadian's answer.致 OP:您应该接受 vadian 的回答。 His was the first correct answer.他是第一个正确答案。

However, I spend some time in my answer explaining Swift closure syntax, so I am going to leave the answer.但是,我在回答中花了一些时间解释 Swift 闭包语法,所以我将留下答案。


You can use the array method sorted() , which takes a closure that compares pairs of objects and returns true if the first item should come first.您可以使用数组方法sorted() ,它接受一个比较对象对的闭包,如果第一个项目应该先出现,则返回 true。

Then you can use the NSString method compare(options:) to do a "numeric" string comparison, where sequences of digits are treated as numbers inside the string.然后您可以使用 NSString 方法compare(options:)进行“数字”字符串比较,其中数字序列被视为字符串中的数字。

Here is a working code snippet that will sort your array:这是一个可以对数组进行排序的工作代码片段:

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, where a closure is an "anonymous function" (a function with no name.) 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。)

Adapting vadian's code that gives the CORRECT answer to my snippet, it would look like this:调整 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)
    }
})

You can rewrite the above with several shortcuts:您可以使用几个快捷方式重写上述内容:

With a "trailing closure" you skip the () that contains the closure as a parameter and just provide the closure in braces after the function name.使用“尾随闭包”,您可以跳过包含闭包作为参数的() ,只需在 function 名称后的大括号中提供闭包。

You can skip the declaration of the parameters and return type of the closure, and skip the return statement:可以跳过闭包的参数和返回类型的声明,也可以跳过return语句:

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

For more complex code like vadian's that gives the correct answer, I suggest not using positional parameters like that.对于像 vadian 这样给出正确答案的更复杂的代码,我建议不要使用这样的位置参数。 Using local variables like first and second make the code easier to read.使用像firstsecond这样的局部变量使代码更易于阅读。

I suggest studying the chapter on Closures in Apple's Swift iBooks carefully until you understand the various ways that closures can be expressed and their different shortcut syntaxes.我建议仔细研究 Apple 的 Swift iBooks 中关于闭包的章节,直到您了解闭包的各种表达方式及其不同的快捷语法。 It's confusing at first, and using closures is fundamental to using Swift.一开始会让人困惑,使用闭包是使用 Swift 的基础。

Welcome to StackOverflow!欢迎来到 StackOverflow!

What do these numbers represent?这些数字代表什么? I would create a struct to model that "thing" (I'll call it Thing for now), and function that can parse a String into a Thing , like so:我将创建一个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)
    }
}

Then, you can just conform to Comparable , defining how you want things to be sorted, by defining the comparison operator < :然后,您可以遵循Comparable ,通过定义比较运算符<来定义您希望如何对事物进行排序:

extension Thing: Comparable {
    static func < (lhs: Thing, rhs: Thing) -> Bool {
        return (lhs.letter, lhs.number) < (rhs.letter, rhs.number)
    }
}

From there, it's just a matter of parsing all your strings into Thing s, and sorting them:从那里开始,只需将所有字符串解析为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: 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")

Welcome to StackOverflow!欢迎来到 StackOverflow!

this is my solution hope it works for you, I just organize first the numbers and next comparate with the alphabeth to create a new array:这是我的解决方案希望它对你有用,我只是先组织数字,然后与字母进行比较以创建一个新数组:

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

Don't forget include this helpers methods in your project不要忘记在你的项目中包含这个帮助方法

    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