簡體   English   中英

根據與特定屬性對應的另一個數組中的值對對象數組進行排序

[英]Sort array of objects based on values in another array that correspond to specific properties

假設從JSON API檢索對象數組:

[
    {
        "id": 48,
        "name": "Bob"
    },
    {
        "id": 198,
        "name": "Dave"
    },
    {
        "id": 2301,
        "name": "Amy"
    },
    {
        "id": 990,
        "name": "Colette"
    }
]

// e.g. for ease of reproduction:

let dataObjects = [
    ["id": 48, "name": "Bob"], 
    ["id": 198, "name": "Dave"], 
    ["id": 2301, "name": "Amy"], 
    ["id": 990, "name": "Colette"]
]

在客戶端上,我想允許用戶重新排序這些對象。 為了保存訂單,我將ID列表存儲在數組中:

let index: [Int] = [48, 990, 2103, 198]

如何根據排序索引中ID的順序對數據對象的原始數組重新排序?

dataObjects.sort({ 
    // magic happens here maybe?
}

最終,我得到:

print(dataObjects)
/* 
[
    ["id": 48, "name": "Bob"], 
    ["id": 990, "name": "Colette"], 
    ["id": 2301, "name": "Amy"], 
    ["id": 198, "name": "Dave"]
]
/*

方法A)將數據解析為簡單的字典,其中字典的鍵是用於對其進行排序的ID:

func sort<Value>(a: [Int: Value], basedOn b: [Int]) -> [(Int, Value)] {
    return a.sort { x, y in
        b.indexOf(x.0) < b.indexOf(y.0)
    }
}

// ....
let a = [48:"Bob", 198:"Dave", 2301:"Amy", 990:"Colette"]
let b = [48, 198, 2301, 990]
sort(a, basedOn: b)

方法B)使用一些自定義DataObject類型:(可能是最好的方法)

struct DataObject {
    let id: Int
    let name: String

    init(_ id: Int, _ name: String) {
        self.id = id
        self.name = name
    }
}

func sort(a: [DataObject], basedOn b: [Int]) -> [DataObject] {
    return a.sort { x, y in
        b.indexOf(x.id) < b.indexOf(y.id)
    }
}


let a = [DataObject(48, "Bob"), DataObject(198, "Dave"), DataObject(2301, "Amy"), DataObject(990, "Colette")]
let b = [48, 198, 2301, 990]

sort(a, basedOn: b)
/* [
     DataObject(id: 48, name: "Bob"), 
     DataObject(id: 990, name: "Colette"), 
     DataObject(id: 198, name: "Dave"), 
     DataObject(id: 2301, name: "Amy")
] */

方法C)使用原始的 json值,可以用一種不太“干凈”的方式完成此操作:

func sort<Value>(a: [[String: Value]], basedOn b: [Int]) -> [[String: Value]] {
    return a.sort { x, y in
        let xId = x["id"] as! Int
        let yId = y["id"] as! Int
        return b.indexOf(xId) < b.indexOf(yId)
    }
}

let dataObjects = [
    ["id": 48, "name": "Bob"],
    ["id": 198, "name": "Dave"],
    ["id": 2301, "name": "Amy"],
    ["id": 990, "name": "Colette"]
]

let b = [48, 198, 2301, 990]

sort(dataObjects, basedOn: b)

您可以受益於Swift的功能支持,並使用map函數遍歷index數組並獲取相應的對象:

let sortedObjects = index.map{ id in
    dataObjects.filter{ $0["id"] as? Int == id }.first
}

這假定在映射數據對象之前已正確計算了index數組。


編輯

感謝user3441734的flatMap建議。 這里有一個解決方案,利用它,基本上它只是更換mapflatMap ,以擺脫可能的nil映射的數組中的值,以及所產生的數組轉換成非自選的數組。

let sortedObjects = index.flatMap{ id in
    dataObjects.filter{ $0["id"] as? Int == id }.first
}

如果空index應該導致保留相同的順序,那么我們可以簡單地測試一下:

let sortedObjects = index.count > 0 ? index.flatMap{ id in
    dataObjects.filter{ $0["id"] as? Int == id }.first
} : dataObjects

您不需要保留帶有可以按所需對象排序的索引的數組,可以說您具有以下結構:

struct DataObject {
   var id: Int
   var name: String
}

var data = [DataObject]()
data.append(DataObject(id: 48, name: "Bob"))
data.append(DataObject(id: 198, name: "Dave"))
data.append(DataObject(id: 2301, name: "Amy"))
data.append(DataObject(id: 990, name: "Colette"))

您可以使用sort函數對結果進行排序並將其返回到其他數組中,或者如果要使其就位,則可以使用sorted函數

// ordered by id
var sortedData = data.sort { index.indexOf($0.id) < index.indexOf($1.id) }

希望對您有所幫助。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM