我不是计算机科学专业的人,但我认为反复调用
indexOf
方法是浪费的。正确的方法应该是预先遍历模板数组(在这种情况下是
ids
),建立一个将每个元素与其在数组中的位置关联起来的字典:
let ids = ["1", "2", "3"]
var d = [String:Int]()
for (ix,id) in ids.enumerated() {
d[id] = ix
}
现在我们有一个字典,字典中的查找速度很快。因此,我们可以使用每个对象的
id
作为键,并根据相应的值进行排序。假设这是我们最初的对象数组:
class MyObject {
let id: String
init(id:String) {self.id = id}
}
let objects = [MyObject(id:"3"), MyObject(id:"1"), MyObject(id:"2")]
现在排序只需要一行代码:
let objectsSorted = objects.sorted { d[$0.id]! < d[$1.id]! }
这里的优势特别明显,如果您知道您将经常使用
ids
作为模板,因为您只需要形成一次字典
d
,现在您可以根据该模板随意排序多次。实际上,字典记忆了排序顺序。(当然,我没有考虑字典查找失败时会发生什么;我们只是崩溃了。)
我们可以根据这个事实推广这种方法,基于模板数组中的值必须是可哈希的才能作为字典键:
struct Cosorter<K:Hashable> {
let d : [K:Int]
init(_ arr:[K]) {
var dd = [K:Int]()
for (ix,val) in arr.enumerated() {
dd[val] = ix
}
self.d = dd
}
func lt(_ v1:K, _ v2:K) -> Bool {
return self.d[v1]! < self.d[v2]!
}
}
现在每个模板都被转换为一个已初始化了模板数组的Cosorter实例,从而导致字典被准备好,只需一次即可:
let idsTemplate = Cosorter(ids)
任何时候,我们想要在该模板上进行排序,只需使用该模板的
lt
作为排序函数即可:
let objectsSorted = objects.sorted {idsTemplate.lt($0.id,$1.id)}
let sorted = objects.sorted { ids.index(of: $0.id)! < ids.index(of: $1.id)! }
。 - Banana