【问题标题】:Is there any easy way to merge two arrays in swift along with removing duplicates?有没有什么简单的方法可以快速合并两个数组以及删除重复项?
【发布时间】:2017-01-08 01:37:44
【问题描述】:

基本上我需要一个不附加 duplicate 元素的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

【问题讨论】:

    标签: arrays swift swift2


    【解决方案1】:

    可以创建一个数组扩展来执行此操作。

    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 元素有用。

    【讨论】:

    • 我收到此错误:“生成器”不是“C”的成员类型
    【解决方案2】:

    简单地说:

    let unique = Array(Set(a + b))
    

    【讨论】:

    • 尽管这很优雅,只是一个想法:-let unique = Array(Set(a + b)).sort() 看起来会更好......
    • 然而,这并没有保持a 元素的顺序,同时将b 的元素添加到它的末尾,有人可能会说这是预期的行为。由于使用了Set,订单无法维护。
    • 你的意思是let unique = Array(Set(a + b)).sorted() 吗?
    【解决方案3】:

    这通常称为union,在 Swift 中可以使用Set

    let a = [1, 2, 3]
    let b = [3, 4, 5]
    
    let set = Set(a)
    let union = set.union(b)
    

    然后你可以将集合转换为数组:

    let result = Array(union)
    

    【讨论】:

    • 虽然想法很清楚,但您的示例无法编译 - 数字不是字符串。同样union返回一个新的集合并保持接收者不变。
    • @MartinR 啊,你是对的。这就是我得到的快速复制/粘贴,固定的。
    【解决方案4】:

    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 属性可能相同但其他对象可能不同,这点很重要。

    【讨论】:

      【解决方案5】:

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

      如前所述:传递给函数的数组是将最终数组中省略的对象数组

      【讨论】:

        【解决方案6】:

        斯威夫特 5 更新了

        如果您需要合并多个数组。

        func combine<T>(_ arrays: Array<T>?...) -> Set<T> {
            return arrays.compactMap{$0}.compactMap{Set($0)}.reduce(Set<T>()){$0.union($1)}
        }
        

        用法示例:

        1.

            let stringArray1 = ["blue", "red", "green"]
            let stringArray2 = ["white", "blue", "black"]
            
            let combinedStringSet = combine(stringArray1, stringArray2)
        
            // Result: {"green", "blue", "red", "black", "white"}
        
            let numericArray1 = [1, 3, 5, 7]
            let numericArray2 = [2, 4, 6, 7, 8]
            let numericArray3 = [2, 9, 6, 10, 8]
            let numericArray4: Array<Int>? = nil
            
            let combinedNumericArray = Array(combine(numericArray1, numericArray2, numericArray3, numericArray4)).sorted()
        
            // Result: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
        

        【讨论】:

          【解决方案7】:

          我将我对序列和数组的扩展与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)
              }
          }
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2022-06-11
            • 2014-08-09
            • 1970-01-01
            • 2014-01-28
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多