SwiftyJD
SwiftyJD

Reputation: 5441

How to check if 2 arrays have the same element and if it does, delete that element from one of the arrays?

I currently have 2 arrays, one called rewardsArray and one called expiredRewardsArray. The rewardsArray I'm getting from an api thats fetched every time I connect. The expiredRewardsArray I save locally. What I'm trying to do is in the viewDidLoad, after I retrieve the rewardsArray data I want to compare it to the expiredRewardsArray's data. If there is a match I want to remove the item from the rewardsArray. This is what I have so far but it never goes inside the "if let" brackets so it's not removing the item from the rewardsArray:

 func rewardsMinusExpired () {

    expiredRewardsArray = rewardManager.getExpiredRewards()

    for expiredReward in expiredRewardsArray {
      if let ex = rewardsArray.indexOf(expiredReward){

        print("Expired Reward to be removed: \(ex)")

        rewardsArray.removeAtIndex(ex)

        rewardsTableView.reloadData()
      }
    }
  }

Each item in the array has an id, I use that to see if the item is in the expiredRewardsArray:

 for expiredReward in expiredRewardsArray {
       print("This is an expired reward: \(expiredReward.id)")
    }

Upvotes: 1

Views: 149

Answers (4)

Søren Mortensen
Søren Mortensen

Reputation: 1755

If expiredRewardsArray and rewardsArray are arrays of objects, then you'll need to compare the elements using their id property to compare them, rather than indexOf(_:). The reason for this is that objects are reference types, so you can have two different objects with identical properties, but if they're not the same object, indexOf(_:) will treat them as separate entities.

Try this code instead:

func rewardsMinusExpired() {
    expiredRewardsArray = rewardManager.getExpiredRewards()

    rewardsArray = rewardsArray.filter { reward in
        let isExpired = expiredRewardsArray.contains { expiredReward in
            return expiredReward.id == reward.id
        }
        return !isExpired
    }
}

Upvotes: 0

Sandeep
Sandeep

Reputation: 21144

You should really use swift method filter in cases like this. This can be easily solved as this,

func rewardMinusExpired() {
    let notExpiredRewards = rewardsArray.filter { a in
        return !expiredRewardArray.contains(a)
    }
}

Upvotes: 2

Yannick
Yannick

Reputation: 3278

for item in expiredRewardsArray {
    if let index = rewardsArray.index(of: item) { 
        //found the item
        rewardsArray.remove(at: index)
    }
}

This will find the item and delete it from the rewardsArray

UPDATE:

You say that each item has an id. If with the code above the if let block is never called than you can be sure that the items aren't actually the same or you don't have any equal items.

for itemOne in expiredRewardsArray {
    for itemTwo in rewardsArray { 
        if itemOne.id == itemTwo.id {
            rewardsArray.remove(at: index)
        }
    }
}

Not very performant but it does its job and keeps the order

Upvotes: 2

Alexander
Alexander

Reputation: 63167

Here's a solution that uses Set arithmetic. As a consequence, it's really fast, but it will not preserve the ordering of elements, and it will clobber any duplicates. It runs in linear time (O(n)), whereas a naive approach would be O(n^2).

let unexpiredRewards = Set(rewardsArray).subtract(Set(ExpiredRewards))

Upvotes: 3

Related Questions