SomeGuy
SomeGuy

Reputation: 3845

How can I compare an array of structs to see which elements are different?

I have two arrays of structs which contains a couple doubles that I want to compare.

I want to compare each space of the older array to the newer, and see which indexes contain structs in which both doubles match, and remove them from the newer of the two arrays. I want the end result to be an array with only the sets of doubles that are not included in the first array. In other words, both arrays have different sets.

I originally tried iterating through each index one at a time, but removing an index messes up the loop. So I tried creating a third array to add the ones that aren't the same, but I'm having trouble figuring out how to efficiently find out which are different.

Are there any quick Swift solutions that anyone knows of that could help with this problem efficiently?

This is the code I have so far, but I'm sort of stuck here because the result will be nothing near what I'm looking for...

if userPosts.count == 0 {
        userPosts = newArrayOfUserPosts
    }
    if newArrayOfUserPosts.count > 0 {
        for currentCount in 0...userPosts.count - 1 {

            for eachElement in 0...newArrayOfUserPosts.count - 1 {

                if newArrayOfUserPosts[eachElement].postLatitude != userPosts[currentCount].postLatitude && newArrayOfUserPosts[eachElement].postLongitude != userPosts[currentCount].postLongitude {

                }
            }
        }
    }

Upvotes: 5

Views: 2904

Answers (3)

Vinoth Anandan
Vinoth Anandan

Reputation: 1287

Add Equatable to your struct.

struct Refinement: Equatable {
    let key: String
    var value: String
}

If you want to add own condition then add

func == (leftHandSide: Refinement, rightHandSide: Refinement) -> Bool {
    return (leftHandSide.key == rightHandSide.key) && (leftHandSide.value == rightHandSide.value)
}

Or else it will check all values in struct by default.

Then check the array by normal ==

if expectedFacetRefinements == facetRefinements {
    print("true")
} else {
    print("false")
}

Upvotes: 0

oisdk
oisdk

Reputation: 10091

let firstArray = [1, 2, 3, 4, 5, 6]

let secondArray = [3, 4, 5, 6, 7, 8]

secondArray.filter{!contains(firstArray, $0)} //[7, 8]

This takes the second array, and removes everything that's in the first array. This only works on things that are Equatable, though. To make your struct Equatable on some variable in it, you have to implement ==, based on what you think makes two structs the same. Here's an example:

struct Person : Equatable {
  let name: String
  let age: Int
}

func == (leftHandSide: Person, rightHandSide: Person) -> Bool {
  return leftHandSide.name == rightHandSide.name
}

There's a struct, Person. In it, you can have a person's name, and their age. We can decide to identify people based on their name, which is why our == function works on .name.

Here's how it would work with the filtering:

let youngBarry = Person(name: "Barry", age: 25)
let joanna = Person(name: "Joanna", age: 32)
let oldBarry = Person(name: "Barry", age: 44)

let firstArray = [youngBarry]

let secondArray = [oldBarry, joanna]

let filteredSecondArray = secondArray.filter{!contains(firstArray, $0)} //Joanna

When we want to remove things from the second array that are in the first array, our == function looks at oldBarry and youngBarry, and decides that they're the same, so doesn't include oldBarry in the second.

Now, if you wanted to do more complicated or variable behaviour with your removing, you still can, because "contains" can take a closure. Here's the same code as above, but without == implemented:

let filteredSecondArray = secondArray.filter{
  secondArrayElement in

  !contains(firstArray) {

    firstArrayElement in

    return secondArrayElement.name == firstArrayElement.name

  }

}

Your use case looks like it's more suited to implementing Equatable, though. Here's how you would do that.:

extension YourStruct : Equatable {}

func == (lhs: YourStruct, rhs: YourStruct) -> Bool {
  return lhs.postLatitude == rhs.postLatitude && lhs.postLongitude == rhs.postLongitude
}

And then just:

let filteredNewArrayOfUserPosts = newArrayOfUserPosts.filter{!contains(userPosts, $0)}

Upvotes: 1

ABakerSmith
ABakerSmith

Reputation: 22939

If I understand your question correctly, you could use a Set and the subtract method to get the difference in the arrays. Here's an example using Set<Int>:

let oldArray = [0, 2, 7, 5, 10]
let newArray = [0, 2, 7, 5, 10, 11, 8, 20]

let oldSet = Set(oldArray)
let newSet = Set(newArray)

Array(newSet.subtract(oldSet)) // [20, 11, 8]

Or if you wanted it on one line:

Array(Set(newArray).subtract(Set(oldArray))) // [20, 11, 8]

For this to work you'll need to make your struct conform to Hashable.

For more information on Set have a look at The Swift Programming Guide: Collection Types.

Upvotes: 3

Related Questions