ixany
ixany

Reputation: 6040

Swift: HowTo get the difference between two struct-arrays

I have two custom struct-arrays...

struct CarStruct {
    var name : String?
    var speed : Int?
}

var allCarsArr = [CarStruct]() // should contain a lot of CarStructs
var newCarsArr = [CarStruct]() // contains only a few

I want to add the newCarsArr to allCarsArr.

But before that I need to prove that newCarsArr does not contain structs which are already in allCarsArr.

So how can I get all the structs out of newCarsArr which are not in allCarsArr?

Upvotes: 1

Views: 1244

Answers (2)

dfrib
dfrib

Reputation: 73186

As an alternative to working with sets (conforming CarStruct to Hashable), you could settle for conformance to Equatable and simply check the allCarsArr for duplicates of each car to be added from newCarsArr.

/* (example of) conformance to Equatable */
func == (lhs: CarStruct, rhs: CarStruct) -> Bool {
    return lhsName == rhsName && lhsSpeed == rhsSpeed
}

struct CarStruct : Equatable {
    var name : String?
    var speed : Int?
}

var allCarsArr = [CarStruct]()
var newCarsArr = [CarStruct]()

allCarsArr.append(CarStruct(name: "Volvo", speed: 42))
allCarsArr.append(CarStruct(name: "BMW", speed: 50))
newCarsArr.append(CarStruct(name: "BMW", speed: 80))
newCarsArr.append(CarStruct(name: "BMW", speed: 50)) // <-- duplicate

/* Add only cars from newCarsArr to allCarsArr if they don't 
   exist, priorly, in the latter */
newCarsArr.forEach { allCarsArr.contains($0) ? () : allCarsArr.append($0) }

If you work with large arrays, however, a better option for uniqueness is probably to use conformance to Hashable and working with a set or dictionary (as the above will, if allCarsArr grows very large, possibly yield an unwanted overhead), as is described in Kenneth Bruno:s solution above.

Upvotes: 2

user887210
user887210

Reputation:

You should add the Equatable protocol as an extension to your class. This is an excellent article explaining it:

Every Value Type Should Be Equatable

Then you can add both arrays to a Set and it will naturally exclude duplicates. You also need to adhere to Hashable in order to put the value in a Set but there's a simple trick of converting the value to a string and getting the hashValue of that.

struct CarStruct {
  var name : String?
  var speed : Int?
}

extension CarStruct: Hashable, Equatable {
  // For Hashable
  var hashValue:Int { return "\(self.name),\(self.speed)".hashValue }
}

// For Equatable
func ==(lhs:CarStruct, rhs:CarStruct) -> Bool {
  return lhs.name == rhs.name && lhs.speed == rhs.speed
}

var allCarsArr = [CarStruct]() // should contain a lot of CarStructs
let newCarsArr = [CarStruct]() // contains only a few

allCarsArr = Array(Set<CarStruct>(allCarsArr).union(newCarsArr))

Upvotes: 4

Related Questions