对带有异常的字符串数组进行排序 Swift

Posted

技术标签:

【中文标题】对带有异常的字符串数组进行排序 Swift【英文标题】:Sort string array with exceptions Swift 【发布时间】:2022-01-20 00:54:57 【问题描述】:

我想按字母顺序对字符串数组进行排序,但有一个例外是某些元素应始终在数组中排在第一位和第二位。以下是数组的元素:

["cat", "dog", "bird", "zebra", "elephant"]

我希望它按字母顺序排序,但 zebra 始终排在第一位,cat 始终排在第二位,因此排序后应如下所示:

["zebra", "cat", "bird", "dog", "elephant"]

这就是我的处理方式:

    let animals = ["cat", "dog", "bird", "zebra", "elephant"]
    
    animals = animals.sorted(by:  first, second in
        if first == "zebra" return true
        if first == "cat" return true
        return first < second
    )

它首先返回斑马,但不是猫第二

【问题讨论】:

我建议将你不想开始的那些移到一个单独的数组中。然后故事数组。 @SathyaBaman 应该有一种使用排序方法的方法 【参考方案1】:

当元素按升序排列时,传递给sorted(by:) 的闭包应该返回true,否则返回false。除非同时检查第一个值和第二个值,否则无法判断元素是否按升序排列。这就是为什么当第一个值为“zebra”或“cat”时返回 true 不起作用的原因——并不是所有的基础都被覆盖了。

一种解决方案是使用switch 语句根据您正在查看的值指定比较逻辑:

let animals = ["cat", "dog", "bird", "zebra", "elephant"].sorted 
    switch ($0, $1) 
    case ("zebra", "cat"): // zebra is before cat
        return true
    case ("cat", "zebra"): // cat is not before zebra
        return false
    case ("cat", _), ("zebra", _): // zebra/cat are before everything
        return true
    case (_, "cat"), (_, "zebra"): // zebra/cat are not after anything
        return false
    case let (lhs, rhs): // alphabetical order
        return lhs < rhs
    

// ["zebra", "cat", "bird", "dog", "elephant"]

如果这看起来有点过度设计,那是因为它是。像这样覆盖你的所有基础是很困难的,所以我绝对建议你看看你的用例,并考虑你是否真的需要这样做。如果你能摆脱一些更简单的事情,那可能是你最好的选择。例如:

let animals = ["zebra", "cat"] + ["dog", "bird", "elephant"].sorted()
// ["zebra", "cat", "bird", "dog", "elephant"]

或者,如果 animals 数组无法修改,另一种选择是硬编码异常:

let exceptions = ["zebra", "cat"]
let otherAnimals = animals.filter  !exceptions.contains($0) .sorted()
let sortedResult = exceptions + otherAnimals
// ["zebra", "cat", "bird", "dog", "elephant"]

编辑: 一条现已删除的评论质疑switch 语句方法的可靠性。我用animals 数组的所有可能顺序对其进行了测试,每次都返回正确的结果。

【讨论】:

【参考方案2】:

您可以使用枚举首先按 case 声明顺序进行比较,然后按字典顺序按有效负载值进行比较的事实。此功能在 Swift 5.3 中实现,请参阅

SE-0266 Synthesized Comparable conformance for enum types

如果我们定义一个枚举类型,“斑马”和“猫”的情况在前

enum AnimalOrder: Comparable 
    case zebra
    case cat
    case other(String)
    
    init(animal: String) 
        switch animal 
        case "zebra": self = .zebra
        case "cat": self = .cat
        default: self = .other(animal)
        
    

然后只需使用

即可实现所需的排序
let animals = ["cat", "dog", "bird", "zebra", "elephant"]
let sorted = animals.sorted(by: 
    AnimalOrder(animal: $0) < AnimalOrder(animal: $1)
)

print(sorted) // ["zebra", "cat", "bird", "dog", "elephant"]

这种方法可以很容易地扩展到涵盖更多“特殊情况”。

【讨论】:

【参考方案3】:

你想要的答案是:

var animals = ["cat", "dog", "bird", "zebra", "elephant"]

animals = animals.sorted(by:  first, second in
    if first == "cat" && second == "zebra" return false;
    if second == "cat" && first == "zebra" return true;                          
    if first == "zebra" || first == "cat" return true;
    if second == "zebra" || second == "cat" return false;
    
    return first < second
)

您甚至可以在排序之前尝试调用animals.shuffle(),以检查排序是否有效,无论输入顺序如何。

这是一种更易读的方法,尽管效率可能较低:

var animals = ["cat", "dog", "bird", "zebra", "elephant"]

animals = animals.sorted();

var wordIndex:Int = animals.firstIndex(where: $0 == "zebra")!;
animals.insert(animals.remove(at: wordIndex), at: 0);

wordIndex = animals.firstIndex(where: $0 == "cat")!;
animals.insert(animals.remove(at: wordIndex), at: 1);

或者,如果您想要更通用的版本:

 func sortAndPrepend(inputArr: [String], prependWords: [String]) -> [String]
    var array = inputArr.sorted();
    
    var wordIndex:Int;
    for i in 0...prependWords.count-1 
        wordIndex = array.firstIndex(where: $0 == prependWords[i]) ?? -1;
        if (wordIndex != -1) 
            array.insert(array.remove(at: wordIndex), at: i);
        
    
    return array;

【讨论】:

以上是关于对带有异常的字符串数组进行排序 Swift的主要内容,如果未能解决你的问题,请参考以下文章

求C语言编程编写函数sort:对数组a中的数进行从小到大排序

对字符串中字符进行自然顺序排序(基本类型排序)-冒泡算法实现

如何对表示数字(正数和负数以及小数部分)的字符串数组进行排序?

通过从另一个数组排序来对Swift数组进行排序

带有数字签名的 Swift 签名字符串

如何在 swift 中按字母顺序对 JSON 字符串进行排序?