我有一个不同类型的异构集合,它们都遵循相同的协议。我想按类型然后按名称属性对数组进行排序。例如,我希望按以下顺序按类型对这一系列动物进行排序:“狗”,“鸟”和“鱼”,如果它们的类型相同,则我要按名称进行排序。这是代码:
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多种不同的类型,所以这种重复感觉非常重复。没有太多重复的代码,我该怎么做?
答案 0 :(得分:3)
使用[Animal.Type]
建立排序,然后首先比较相等类型以决定是否需要按name
或type
进行排序。
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
}
}
注释:
name
排序到数组的末尾。您可能要添加:
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 构建。
元组比较(如@Hamish用this answer解释的那样)可用于将上面的if
语句替换为:
return (firstIndex, first.name) < (secondIndex, second.name)
感谢提醒,@ MartinR!
答案 1 :(得分:2)
如果要通过属性Animal
对type
个对象的异类进行排序,则该属性应在协议中。一旦做出更改,这将变得微不足道。