簡體   English   中英

Swift:根據唯一值合並數組中的 2 個或更多元素自定義對象

[英]Swift: Merging 2 or more elements custom objects in array based on unique value

下面是我的自定義對象類。

class UserGroups: NSObject {
    let groupName: String
    let users: [CheckIn]?

    init(json:JSON) {
        self.groupName = json[Constants.Models.UserGroups.groupName].stringValue
        self.users = UserGroups.getUserGroupsList(jsonArray: json[Constants.Models.UserGroups.users].arrayValue)
    }

    class func getUserGroupsList(jsonArray: [JSON]) -> [CheckIn]{
        return jsonArray.flatMap({ (jsonItem: JSON) -> CheckIn in
            return CheckIn(json: jsonItem)
        })
    }
}

我有一組上述自定義對象。 如何通過合並具有相同groupName的每個對象的用戶將 2 個或更多自定義對象合並為一個對象。

以下是我的簽到模型:

類簽入:NSObject {

let id: String
let firstName: String
let lastName: String
let latitude: String
let longitude: String
let hint: String

init(json: JSON) {
    self.id = json[Constants.Models.CheckIn.id].stringValue
    self.firstName = json[Constants.Models.CheckIn.firstName].stringValue
    self.lastName = json[Constants.Models.CheckIn.lastName].stringValue
    self.hint = json[Constants.Models.CheckIn.hint].stringValue
    self.latitude = json["location"][Constants.Models.CheckIn.latitude].stringValue
    self.longitude = json["location"][Constants.Models.CheckIn.longitude].stringValue
}

}

id字段在 CheckIn 中不是唯一的。

這是一個稍微簡化的示例,展示了如何組合具有相同組名的組。

這是UserGroup類。 users現在是一個變量 ( var ),因為我們將向組添加元素以組合它們。

class UserGroups: NSObject {
    let groupName: String
    var users: [String]?

    init(groupName: String, users: [String]?) {
        self.groupName = groupName
        self.users = users
    }
}

這是三個組,其中兩個共享相同的組名稱Blues

let group1 = UserGroups(groupName: "Blues", users: ["Tom", "Huck", "Jim"])
let group2 = UserGroups(groupName: "Reds", users: ["Jo", "Ben", "Tommy"])
let group3 = UserGroups(groupName: "Blues", users: ["Polly", "Watson", "Douglas"])

接下來,我們將把所有組放在一個數組中。

let allGroups = [group1, group2, group3]

在這里,我們使用 Swift 的reduce函數來允許我們將數組縮減為僅具有唯一組名稱的組。

let compacted = allGroups.reduce([UserGroups](), { partialResult, group in

    var dupe = partialResult.filter {$0.groupName == group.groupName }.first
    if let dupeGroup = dupe {
        dupeGroup.users?.append(contentsOf: group.users ?? [])
        return partialResult
    } else {
        var newPartialResult = partialResult
        newPartialResult.append(group)
        return newPartialResult
    }
})

該數組現在被簡化為唯一的組,我們在 Swift 的map函數的幫助下打印出所有組及其用戶。

print(compacted.map { $0.users })

// Prints [
Optional(["Tom", "Huck", "Jim", "Polly", "Watson", "Douglas"]), 
Optional(["Jo", "Ben", "Tommy"])
]

解決方案

您沒有包含CheckIn模型,但我假設它具有某種對每個用戶都是唯一的 id 字段。 我們將使用它使對象Hashable

// Add this to your file outside of the UserGroups class
extension CheckIn: Hashable {
    var hashValue: Int { return self.id }
}

使其Hashable允許您將Array轉換為Set ,這不允許重復並將以非常有效的方式刪除它們。

// Change getUserGroupsList as follows
class func getUserGroupsList(jsonArray: [JSON]) -> [CheckIn] {
    return Array(Set(jsonArray.flatMap({ (jsonItem: JSON) -> CheckIn in
        return CheckIn(json: jsonItem)
    })))
}

可選注意事項

順便說一句,如果您來自另一種語言,Swift 為您提供了很好的類型推斷和閉包參數的默認名稱( $0是第一個參數)。 您可能可以使代碼不那么冗長,但這是首選的品味問題。

class func getUserGroupsList(jsonArray: [JSON]) -> [CheckIn] {
    return Array(Set(jsonArray.flatMap { CheckIn(json: $0) }))
}

還要考慮您是否真的希望返回值是一個數組。 如果您希望列表始終具有唯一用戶,則使用Set作為返回類型並放棄轉換回Array效率會更高,如下所示:

class func getUserGroupsList(jsonArray: [JSON]) -> Set<CheckIn> {
    return Set(jsonArray.flatMap { CheckIn(json: $0) })
}

最后,考慮您是否真的需要users屬性是可選的。 對於序列類型,通常使用空序列來表示沒有值就足夠了。 根據您的情況,這可能會簡化您的代碼。 最終版本如下所示:

class UserGroups: NSObject {
    let groupName: String
    let users: Set<CheckIn>

    init(json:JSON) {
        self.groupName = json[Constants.Models.UserGroups.groupName].stringValue
        self.users = UserGroups.getUserGroupsList(jsonArray: json[Constants.Models.UserGroups.users].arrayValue)
    }

    class func getUserGroupsList(jsonArray: [JSON]) -> Set<CheckIn> {
        return Set(jsonArray.flatMap { CheckIn(json: $0) })
    }
}

維持秩序

需要注意的是Set不維護項目的順序。 如果組的順序確實很重要,我們可以改用這個解決方案:

class func getUserGroupsList(jsonArray: [JSON]) -> [CheckIn] {
    var encountered: Set<CheckIn> = []
    return jsonArray.flatMap { CheckIn(json: $0) }.filter { encountered.update(with: $0) == nil }
}

在這個版本中,我們仍然使用一個集合,但只是為了維護我們已經遇到的一組項目。 如果集合已經在集合中,則update方法返回相同的值,如果是第一次插入,則返回nil 我們使用它來過濾我們的數組到那些第一次遇到的項目,同時將它們添加到遇到的項目集合中,以便在隨后再次遇到它們時將它們過濾掉。

暫無
暫無

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

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