基本上我需要一个appendContentsOf:
的版本,它不附加重复的元素。
示例
var a = [1, 2, 3]
let b = [3, 4, 5]
a.mergeElements(b)
//gives a = [1, 2, 3, 4, 5] //order does not matter
答案 0 :(得分:20)
简单地说:
let unique = Array(Set(a + b))
答案 1 :(得分:5)
这通常称为union,使用Set
可以在Swift中使用:
let a = [1, 2, 3]
let b = [3, 4, 5]
let set = Set(a)
let union = set.union(b)
然后你可以将集合转换为数组:
let result = Array(union)
答案 2 :(得分:4)
Swift 4.0版本
extension Array where Element : Equatable {
public mutating func mergeElements<C : Collection>(newElements: C) where C.Iterator.Element == Element{
let filteredList = newElements.filter({!self.contains($0)})
self.append(contentsOf: filteredList)
}
}
如上所述:传递给函数的数组是将从最终数组
中省略的对象数组答案 3 :(得分:3)
Swift 3.0 版本。
extension Array where Element : Equatable{
public mutating func mergeElements<C : Collection>(newElements: C) where C.Generator.Element == Element{
let filteredList = newElements.filter({!self.contains($0)})
self.append(contentsOf: filteredList)
}
}
注意:值得一提的是,传递给函数的数组是最终数组中将省略的对象数组。重要的是,如果合并一个对象数组,其中Equatable
属性可能相同但其他属性可能不同。
答案 4 :(得分:1)
可以创建一个Array扩展来执行此操作。
extension Array where Element : Equatable{
public mutating func mergeElements<C : CollectionType where C.Generator.Element == Element>(newElements: C){
let filteredList = newElements.filter({!self.contains($0)})
self.appendContentsOf(filteredList)
}
}
当然,这仅适用于Equatable
元素。
答案 5 :(得分:0)
Swift 4
func combine(_ sets: Set<String>?...) -> Set<String> {
return sets.compactMap{$0}.reduce(Set<String>()){$0.union($1)}
}
答案 6 :(得分:0)
我将Sequence和Array的扩展名与this answer结合使用,以在通过单个属性将数组与自定义对象合并时提供简单的语法:
extension Dictionary {
init<S>(_ values: S, uniquelyKeyedBy keyPath: KeyPath<S.Element, Key>) where S : Sequence, S.Element == Value {
let keys = values.map { $0[keyPath: keyPath] }
self.init(uniqueKeysWithValues: zip(keys, values))
}
}
// Unordered example
extension Sequence {
func merge<T: Sequence, U: Hashable>(mergeWith: T, uniquelyKeyedBy: KeyPath<T.Element, U>) -> [Element] where T.Element == Element {
let dictOld = Dictionary(self, uniquelyKeyedBy: uniquelyKeyedBy)
let dictNew = Dictionary(mergeWith, uniquelyKeyedBy: uniquelyKeyedBy)
return dictNew.merging(dictOld, uniquingKeysWith: { old, new in old }).map { $0.value }
}
}
// Ordered example
extension Array {
mutating func mergeWithOrdering<U: Hashable>(mergeWith: Array, uniquelyKeyedBy: KeyPath<Array.Element, U>) {
let dictNew = Dictionary(mergeWith, uniquelyKeyedBy: uniquelyKeyedBy)
for (key, value) in dictNew {
guard let index = firstIndex(where: { $0[keyPath: uniquelyKeyedBy] == key }) else {
append(value)
continue
}
self[index] = value
}
}
}
测试:
@testable import // Your project name
import XCTest
struct SomeStruct: Hashable {
let id: Int
let name: String
}
class MergeTest: XCTestCase {
let someStruct1 = SomeStruct(id: 1, name: "1")
let someStruct2 = SomeStruct(id: 2, name: "2")
let someStruct3 = SomeStruct(id: 2, name: "3")
let someStruct4 = SomeStruct(id: 4, name: "4")
var arrayA: [SomeStruct]!
var arrayB: [SomeStruct]!
override func setUp() {
arrayA = [someStruct1, someStruct2]
arrayB = [someStruct3, someStruct4]
}
func testMerging() {
arrayA = arrayA.merge(mergeWith: arrayB, uniquelyKeyedBy: \.id)
XCTAssert(arrayA.count == 3)
XCTAssert(arrayA.contains(someStruct1))
XCTAssert(arrayA.contains(someStruct3))
XCTAssert(arrayA.contains(someStruct4))
}
func testMergingWithOrdering() {
arrayA.mergeWithOrdering(mergeWith: arrayB, uniquelyKeyedBy: \.id)
XCTAssert(arrayA.count == 3)
XCTAssert(arrayA[0] == someStruct1)
XCTAssert(arrayA[1] == someStruct3)
XCTAssert(arrayA[2] == someStruct4)
}
}