Arrays 将数组与Swift中的另一个数组进行重新排序

Arrays 将数组与Swift中的另一个数组进行重新排序,arrays,swift,swift3,Arrays,Swift,Swift3,我在Swift中有一个数组,其中包含一些对象的ID,我还有另一个数组,其中包含这些对象及其ID,所以类似这样: class MyObject { let id: String ... } let ids: [String] = ... let objects: [MyObject] = ... 现在ID数组按某种自定义顺序排序,我需要对象数组按相同顺序排序。例如: let ids: [String] = ["1", "2", "3"] let objects: [MyObject

我在Swift中有一个数组,其中包含一些对象的ID,我还有另一个数组,其中包含这些对象及其ID,所以类似这样:

class MyObject {
   let id: String
   ...
}

let ids: [String] = ...
let objects: [MyObject] = ...
现在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]
所以我基本上需要实现这种重新排序方法。
有人对如何在Swift中实现这一点提出了明智的建议吗?我使用的是Swift 3,所以我可以使用所有新的API。

您可以对
对象进行排序
,以便遵循
ids
编写的顺序

let sorted = objects.sort { ids.indexOf($0.id) < ids.indexOf($1.id) }
// [{id "1"}, {id "2"}, {id "3"}]
let sorted=objects.sort{ids.indexOf($0.id)
另一个例子
let id:[String]=[“3”、“2”、“1”]
let对象:[MyObject]=[MyObject(id:“3”)、MyObject(id:“1”)、MyObject(id:“2”)]
让sorted=objects.sort{ids.indexOf($0.id)
该代码在Swift 2.2中


Swift 4.2解决方案

let sorted = objects.sorted { ids.index(of: $0.id)! < ids.index(of: $1.id)! }
let sorted=objects.sorted{ids.index(of:$0.id)!
可能的解决方案:

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 }
let sorted=objects.flatMap{obj in
index(of:obj.id).map{idx-in(obj,idx)}
}.排序(按:{$0.1<$1.1}).map{$0.0}
说明:

  • 首先,将每个对象与相应的 id在数组中的位置,这将给出
    (对象,索引)
    元组
  • 此数组根据索引位置进行排序
  • 最后,再次提取对象
可能的优势:

  • 每个对象在数组中只搜索一次
  • 数组中不存在id的对象将被忽略

请注意,如果在未排序的
中找不到id,则重新排序方法将失败

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
}

我不是一个计算机科学的人,但在我看来,反复调用
indexOf
是一种浪费。当然,正确的方法是预先遍历模板数组一次(本例中为id),构建一个字典,将每个元素与其在数组中的位置关联起来:

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]! }
现在,每个模板都转换为一个使用模板数组初始化的Cosorter实例,从而使字典准备就绪,一旦:

let idsTemplate = Cosorter(ids)
任何时候我们想要对该模板进行排序,我们只需使用该模板的
lt
作为排序函数:

let objectsSorted = objects.sorted {idsTemplate.lt($0.id,$1.id)}

太好了,这正是我要找的!在Swift 3中,这将是
let sorted=objects.sorted{ids.index(of:$0.id)!
@Banana的解决方案也适用于Swift 4,可能会进入可接受的范围answer@DylanReich我刚刚添加了它。这可能是最好的解决方案(尽管乍一看有点难以理解)–请注意,内部的
flatMap
可能只是一个常规的
map
,因为返回的元组是非可选的:)@Hamish:你说得对,谢谢
indexOf
返回一个可选的,但是
map
足以处理这个问题。
let idsTemplate = Cosorter(ids)
let objectsSorted = objects.sorted {idsTemplate.lt($0.id,$1.id)}