Ios Swift:基于唯一值在数组中合并2个或多个元素自定义对象

Ios Swift:基于唯一值在数组中合并2个或多个元素自定义对象,ios,arrays,swift,Ios,Arrays,Swift,下面是我的自定义对象类 class UserGroups: NSObject { let groupName: String let users: [CheckIn]? init(json:JSON) { self.groupName = json[Constants.Models.UserGroups.groupName].stringValue self.users = UserGroups.getUserGroupsList(jso

下面是我的自定义对象类

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)
        })
    }
}
我有一个以上自定义对象的数组。如何通过合并具有相同组名的每个对象的用户,将两个或多个自定义对象合并为一个对象

以下是我的签入模式:

类签入: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字段在签入中不是唯一的。

这里有一个稍微简化的示例,演示如何组合具有相同组名的组

下面是
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函数将数组简化为只有组名唯一的组

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功能的帮助下打印出所有组及其用户

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

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

下面是一个稍微简化的示例,演示如何组合具有相同组名的组

下面是
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函数将数组简化为只有组名唯一的组

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功能的帮助下打印出所有组及其用户

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

// Prints [
Optional(["Tom", "Huck", "Jim", "Polly", "Watson", "Douglas"]), 
Optional(["Jo", "Ben", "Tommy"])
]
解决方案 您没有包括
签入
模型,但我假设它具有某种对每个用户唯一的id字段。我们将使用它使对象可散列:

// Add this to your file outside of the UserGroups class
extension CheckIn: Hashable {
    var hashValue: Int { return self.id }
}
使其可散列允许您将
数组
转换为
集合
,这不允许重复,并将以非常有效的方式删除它们

// 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) }))
}

还考虑是否真的希望返回值是数组。如果您希望列表始终具有唯一的用户,那么使用

集合
作为返回类型并放弃转换回
数组
会更有效率,如下所示:

class func getUserGroupsList(jsonArray: [JSON]) -> Set<CheckIn> {
    return Set(jsonArray.flatMap { CheckIn(json: $0) })
}
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 }
}
class func getUserGroupsList(jsonArray:[JSON])->[CheckIn]{
遇到的变量:Set=[]
返回jsonArray.flatMap{CheckIn(json:$0)}.filter{遇到.更新(with:$0)==nil}
}
在这个版本中,我们仍然使用一个集合,但只维护我们已经遇到的一组项。集合上的
update
方法如果已经在集合中,则返回相同的值;如果第一次插入,则返回
nil
。我们使用它将数组过滤到第一次遇到的项目,同时将它们添加到遇到的项目集中,以便在随后再次遇到它们时将它们过滤掉。

解决方案 您没有包括
签入
模型,但我假设它具有某种对每个用户唯一的id字段。我们将使用它使对象可散列:

// Add this to your file outside of the UserGroups class
extension CheckIn: Hashable {
    var hashValue: Int { return self.id }
}
使其可散列允许您将
数组
转换为
集合
,这不允许重复,并将以非常有效的方式删除它们

// 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) }))
}

还考虑是否真的希望返回值是数组。如果您希望列表始终具有唯一的用户,那么使用

集合
作为返回类型并放弃转换回
数组
会更有效率,如下所示:

class func getUserGroupsList(jsonArray: [JSON]) -> Set<CheckIn> {
    return Set(jsonArray.flatMap { CheckIn(json: $0) })
}
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 }
}
class func getUserGroupsList(jsonArray:[JSON])->[CheckIn]{
遇到的变量:Set=[]
返回jsonArray.flatMap{CheckIn(json:$0)}.filter{遇到.更新(with:$0)==nil}
}

在这个版本中,我们仍然使用一个集合,但只维护我们已经遇到的一组项。集合上的
update
方法如果已经在集合中,则返回相同的值;如果第一次插入,则返回
nil
。我们使用它将数组过滤到第一次遇到的项目,同时将它们添加到遇到的项目集中,以便在随后再次遇到它们时将它们过滤掉。

Thank@hashemi。我添加了有问题的签入模型。id字段在中不是唯一的CheckIn@niks为了澄清,您正在尝试确保用户是唯一的,对吗?除了
id
之外,还有其他方法可以确定两个用户是相同的吗?什么是复制品?谢谢@hashemi。我添加了有问题的签入模型。id字段在中不是唯一的CheckIn@niks为了澄清,您正在尝试确保用户是唯一的,对吗?除了
id
之外,还有其他方法可以确定两个用户是相同的吗?什么是复制品?回答得很好,w