我在Swift中有一个包含一些对象id的数组,我有另一个包含这些对象及其id的数组,所以像这样:
let ids: [String] = ["1", "2", "3"]
let objects: [MyObject] = [obj3, obj1, obj2]
// obj1.id = "1"
// obj2.id = "2"
// obj3.id = "3"
objects.reorder(template: ids)
// Now objects = [obj1, obj2, obj3]
现在,id的数组按照某种自定义顺序排序,我需要以相同的顺序对对象数组进行排序。例如:
{{1}}
所以我基本上需要实现这个重新排序方法。 有没有人有一个聪明的建议如何在Swift中做到这一点?我正在使用Swift 3,所以我可以使用所有新的API。
答案 0 :(得分:5)
您可以对objects
进行排序,以便按照ids
撰写
let sorted = objects.sort { ids.indexOf($0.id) < ids.indexOf($1.id) }
// [{id "1"}, {id "2"}, {id "3"}]
let ids: [String] = ["3", "2", "1"]
let objects: [MyObject] = [MyObject(id: "3"), MyObject(id: "1"), MyObject(id: "2")]
let sorted = objects.sort { ids.indexOf($0.id) < ids.indexOf($1.id) }
// [{id "3"}, {id "2"}, {id "1"}]
此代码在Swift 2.2中
Swift 4.2解决方案
let sorted = objects.sorted { ids.index(of: $0.id)! < ids.index(of: $1.id)! }
答案 1 :(得分:5)
可能的解决方案:
let sorted = objects.flatMap { obj in
ids.index(of: obj.id).map { idx in (obj, idx) }
}.sorted(by: { $0.1 < $1.1 } ).map { $0.0 }
说明:
(object, index)
元组。可能的优势:
答案 2 :(得分:1)
我不是计算机科学的人,但在我看来,这种反复呼叫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)
任何时候我们想要在该模板上进行cosort,我们只使用该模板的lt
作为排序函数:
let objectsSorted = objects.sorted {idsTemplate.lt($0.id,$1.id)}
答案 3 :(得分:0)
请注意,如果在unsorted
func reorder(items: [MyObject], order : [String]) -> [String] {
var unsorted = items
var ordered : [String] = []
for orderId in order {
let index = unsorted.filter{ $0.id == orderId }.first
let found = unsorted.remove(at: index!)
ordered.append(found)
}
return ordered
}