与Swift中的另一个数组相比重新排序数组

时间:2016-09-01 13:50:59

标签: arrays swift swift3

我在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。

4 个答案:

答案 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 }

说明:

  • 首先,每个对象与相应的一起绑定 id在数组中的位置,这给出了一个数组 (object, index)元组。
  • 此数组按索引位置排序。
  • 最后,再次提取对象。

可能的优势:

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

答案 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

中找不到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
}