Fondamentalement, j'ai besoin d'une version de appendContentsOf:
qui n'ajoute pas duplicate elements.
Exemple
var a = [1, 2, 3]
let b = [3, 4, 5]
a.mergeElements(b)
//gives a = [1, 2, 3, 4, 5] //order does not matter
Une extension Array peut être créée pour cela.
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)
}
}
Bien entendu, cela n’est utile que pour les éléments Equatable
.
Simplement:
let unique = Array(Set(a + b))
Ceci est communément appelé union , ce qui est possible dans Swift en utilisant un Set
:
let a = [1, 2, 3]
let b = [3, 4, 5]
let set = Set(a)
let union = set.union(b)
Ensuite, vous pouvez simplement convertir l'ensemble en un tableau:
let result = Array(union)
Swift 3.0 version de la réponse acceptée.
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)
}
}
Note: / Cela vaut la peine de dire ici que le tableau transmis à la fonction est le tableau d'objets qui sera omis du tableau final. Important si vous fusionnez un tableau d'objets dont la propriété Equatable
peut être la même, mais d'autres peuvent différer.
Swift 4.0 Version
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)
}
}
Comme mentionné: le tableau passé à la fonction est le tableau d'objets qui sera omis du tableau final
J'ai combiné mon extension de Sequence and Array avec this answer pour fournir une syntaxe simple lors de la fusion de tableaux avec des objets personnalisés à l'aide d'une seule propriété:
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
}
}
}
Tester:
@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)
}
}
Swift 4
func combine(_ sets: Set<String>?...) -> Set<String> {
return sets.compactMap{$0}.reduce(Set<String>()){$0.union($1)}
}