不同类型集合元素匹配:如何用Set<A>基于主键更新Array<B>?
用Set匹配主键更新Array的实现方案
这事儿其实挺直观的,核心就是利用主键匹配关联两个集合的元素,再结合Swift值类型和引用类型的特性完成更新。咱们直接上干货:
先明确你的数据结构
先把你给出的结构体和类定义整理成可运行的代码(方便后续对照):
struct A { var name: String var primaryID: Int } class B { var kind: String var primaryID: Int // 给B加初始化方法,方便测试时创建实例 init(kind: String, primaryID: Int) { self.kind = kind self.primaryID = primaryID } }
最优实现思路:先转字典再遍历更新
直接遍历arrayOfB后去setOfA里逐个找匹配元素,虽然能实现,但数据量大时效率很低。更高效的方式是先把setOfA转成以primaryID为key的字典,这样查找匹配元素的时间复杂度直接降到O(1)。
完整代码示例
// 准备测试数据 let setOfA: Set<A> = [ A(name: "Apple", primaryID: 1), A(name: "Banana", primaryID: 2), A(name: "Cherry", primaryID: 3) ] var arrayOfB: [B] = [ B(kind: "Unknown", primaryID: 1), B(kind: "Unknown", primaryID: 2), B(kind: "Unknown", primaryID: 4) // 这个ID在Set里没有,不会被更新 ] // 步骤1:把Set<A>转成[Int: A]字典,用primaryID当key let aDictionary = Dictionary(uniqueKeysWithValues: setOfA.map { ($0.primaryID, $0) }) // 步骤2:遍历arrayOfB,匹配更新 for bElement in arrayOfB { if let matchedA = aDictionary[bElement.primaryID] { // 这里根据你的需求更新B的属性,比如把kind改成A的name bElement.kind = matchedA.name // 如果还有其他属性要更新,继续加在这里就行 } } // 测试输出看看结果 arrayOfB.forEach { print("ID: \($0.primaryID), Kind: \($0.kind)") }
运行这段代码后,输出会是:
ID: 1, Kind: Apple ID: 2, Kind: Banana ID: 4, Kind: Unknown
为什么这么做?
- 字典的查找效率是O(1),比每次在Set里遍历找匹配高效得多,尤其适合元素较多的场景
- 因为
B是引用类型,遍历数组时修改的是实例本身,不需要额外把元素重新赋值回数组,非常方便 - 如果你的
Set<A>里存在primaryID重复的元素(虽然Set要求元素唯一,但若A的primaryID相同但其他属性不同,Set会判定为不同元素),可以用Dictionary(_:uniquingKeysWith:)处理冲突,比如保留最后一个元素:let aDictionary = Dictionary(setOfA.map { ($0.primaryID, $0) }, uniquingKeysWith: { _, last in last })
备选方案:直接遍历Set匹配(适合小数据量)
如果你的集合元素很少,也可以用更直白的写法,虽然效率稍低但代码简单:
for bElement in arrayOfB { if let matchedA = setOfA.first(where: { $0.primaryID == bElement.primaryID }) { bElement.kind = matchedA.name } }
内容的提问来源于stack exchange,提问作者bauerMusic
相关产品推荐
相关产品推荐

