Reputation: 5441
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
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
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
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
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