在Swift

时间:2019-02-08 18:54:14

标签: swift collections

我有一个不同类型的异构集合,它们都遵循相同的协议。我想按类型然后按名称属性对数组进行排序。例如,我希望按以下顺序按类型对这一系列动物进行排序:“狗”,“鸟”和“鱼”,如果它们的类型相同,则我要按名称进行排序。这是代码:

import Foundation

protocol Animal {
    var name: String { get set }
}

class Dog: Animal {
    var name: String

    init(name: String) {
        self.name = name
    }
}

class Bird: Animal {
    var name: String

    init(name: String) {
        self.name = name
    }
}

class Fish: Animal {
    var name: String

    init(name: String) {
        self.name = name
    }
}

let dogA = Dog(name: "A")
let dogB = Dog(name: "B")
let birdA = Bird(name: "A")
let birdB = Bird(name: "B")
let fishA = Fish(name: "A")
let fishB = Fish(name: "B")

let animals: [Animal] = [fishB, fishA, birdB, birdA, dogB, dogA]

let sortedAnimals = animals.sorted { first, second -> Bool in
    if first is Dog && !(second is Dog) {
        return true
    } else if first is Dog && second is Dog {
        return first.name < second.name
    }

    if first is Bird && !(second is Bird) {
        return true
    } else if first is Bird && second is Bird {
        return first.name < second.name
    }

    if first is Fish && !(second is Fish) {
        return true
    } else if first is Fish && second is Fish {
        return first.name < second.name
    }

    return first.name < second.name
}

sortedAnimals

这可行,并导致正确的排序顺序:

{name "A", type "Dog"}
{name "B", type "Dog"}
{name "A", type "Bird"}
{name "B", type "Bird"}
{name "A", type "Fish"}
{name "B", type "Fish"}

但是由于在生产代码中我有30多种不同的类型,所以这种重复感觉非常重复。没有太多重复的代码,我该怎么做?

2 个答案:

答案 0 :(得分:3)

使用[Animal.Type]建立排序,然后首先比较相等类型以决定是否需要按nametype进行排序。

let order: [Animal.Type] = [Dog.self, Bird.self, Fish.self]

let sortedAnimals = animals.sorted { first, second -> Bool in
    let firstIndex = order.firstIndex { $0 == type(of: first) } ?? Int.max
    let secondIndex = order.firstIndex { $0 == type(of: second) } ?? Int.max

    if firstIndex == secondIndex {
        return first.name < second.name
    } else {
        return firstIndex < secondIndex
    }
}

注释:

  1. 按照书面规定,缺失的类型将通过name排序到数组的末尾。
  2. 您可能要添加:

    assert(firstIndex != Int.max, "missing type \(type(of: first)) from order array")
    assert(secondIndex != Int.max, "missing type \(type(of: second)) from order array")
    

    捕获order数组中缺少的类型。尽管您可以强制解开firstIndex(where:)的结果,但是assert可以在 Debug 版本中找到丢失的类型,但是在 Release 构建。

  3. 元组比较(如@Hamish用this answer解释的那样)可用于将上面的if语句替换为:

    return (firstIndex, first.name) < (secondIndex, second.name)
    

    感谢提醒,@ MartinR!

答案 1 :(得分:2)

如果要通过属性Animaltype个对象的异类进行排序,则该属性应在协议中。一旦做出更改,这将变得微不足道。