Search code examples
arraysswiftunique

iOS Swift: How to find unique members of arrays of different types based on specific attributes


Goal: I have two different classes, and two arrays containing members of each class. Using Swift 2.0, I would like to find the unique members of one array compared to the other based on specific attributes of each class.

Example:

class A {
     var name: String
     init(name: String) {
          self.name = name
     }
}

class B {
     var title: String
     init(title: String) {
          self.title = title
     }
}

let aArray = [A(name:"1"), A(name:"2"), A(name:"3"), A(name:"4")]
let bArray = [B(title:"1"), B(title:"2"), B(title:"5")]

So, I'm looking for some operation between aArray and bArray which returns the 3rd and 4th element of aArray, because they are uniquely in aArray, where the basis of comparison is the attributes A.name and B.title.

Of course, reversing the order of the operation would pick out the 3rd element of bArray, because it is uniquely in bArray.

I know I can accomplish the goal straightforwardly using a simple for loop, but I was hoping for something more elegant and more optimized. But if a for loop is as fast or faster than anything fancier, I'm happy to use it just as well.


Solution

  • I'm not sure fancy or elegant this code is, but, we could do something like this:

    let mappedArray = bArray.map { $0.title }
    let filteredArray = aArray.filter { !mappedArray.contains($0.name) }
    

    So when we want the unique elements from aArray, we first map the elements from bArray to get an array of the value we want to actually compare:

    let mappedArray = bArray.map { $0.title }
    

    mappedArray is just an array of strings based on the title property of the objects in bArray.

    Next, we use the filter method to filter objects from aArray. The filter method returns an array with objects that pass the test in our closure. The test we want to apply is objects that are not contained in the mapped array we just built.

    let filteredArray = aArray.filter { !mappedArray.contains($0.name) }
    

    If we want to do it the other way, just change a few things:

    let mappedArray = aArray.map { $0.name }
    let filteredArray = bArray.filter { !mappedArray.contains($0.title) }