1

I have 2 sections in my tableview. Section 0 has data from an array and section 1 has data from an api. Now I want to check if the data from section 0 has a matching data to that of section 1 then I want to remove that particular entry from section 1. Not sure how to do that…

I have 2 arrays which populate data in each of the sections:

filteredSelectedProductList  —> Section 0
productsList —> Section 1

This is the code I have:

      if self.filteredSelectedProductList.isEmpty == false {
        for prod in self.filteredSelectedProductList {  //section 0
          for filtProd in productsList {   //section 1
            if prod.productId == filtProd.productId {
              //Here I want to remove the matching entry from productsList array. How can I do that..?

            }
          }
        }
      }

4 Answers 4

1

You can use filter where not contains,

something like this should work,

var arr1 = [1,3,4,5,6] // array 1 section 0
var arr2 = [2,34,5,6] // array 2 section 1

print(arr2.filter{!arr1.contains($0)}) // [2,34] 

In your case you are using custom model, you can confirm to Equatable and do the following with it, then you can simple use it as i showed you above.

struct MyCustomObject {
    var id: Int // some unique id you can compare things to
}

extension MyCustomObject: Equatable {
    static func == (lhs: MyCustomObject, rhs: MyCustomObject) -> Bool {
        return lhs.id  == rhs.id
    }
}

Usage :

var arra1: [MyCustomObject] = [] // section 0 
var arra2: [MyCustomObject] = [] // section 1 
print(arra2.filter{!arra1.contains($0)}) 
Sign up to request clarification or add additional context in comments.

3 Comments

but aren't these for numbers @Mohmmad S..? I'm having an array of model Products
@asd2 check it out
This doesn't handle arrays with duplicates correctly. Have a look here
1

Swift 4.1

You can do by this way, You just have to put your array instead of this

var array1 = ["45","34","67"] //section 0
var array2 = ["45", "23"] // section 1

array2.removeAll(where: { array1.contains($0) }) // finalArray = ["23"]

Comments

1

You can use removeAll:

productsList.removeAll(where: { filteredSelectedProductList.contains($0) })

To use the contains, your models must conform to Equatable, otherwise you should do like this:

productsList.removeAll(where: { item in filteredSelectedProductList.contains(where: { $0.productId == item.productId }) })

4 Comments

I think removeAll is better, because you want to actually remove items from your array, instead of filtering and returning a new one.
not on you answer but on your comment "I think removeAll is better", it's the same if he sets the result to the same array .
in the iterator and property observers they're pretty much the same time complexity, one is altering the array another one is setting new one, the number of iterators is the same, however filtering in the buffer could be faster imho, as results held hand 'till iterator finished then returns, when removingAll is altering the same addresses while comparing .
Sure, I meant it's better from a logic perspective. What he wants actually do is to remove all elements that match a criteria
-1

Array.contains is an O(n) operation. Meaning that each element in the first array, you may have to search all of the second array. Resulting in O(m * n), m and n being the counts of the arrays, which is not efficient.

A better way would be to:

  • build a dictionary of the occurrences of elements in the first array,
  • then loop through the second array,
  • Append the elements in the second array that don't belong to the first one.

Here a function that does the above steps with a time complexity of O(m + n):

func intersect<T: Hashable>(_ a1: [T], with a2: [T]) -> [T] {

    var result = [T]()
    result.reserveCapacity(a2.count)

    var dict1: [T: Int] = [T: Int].init(minimumCapacity: a1.count)

    for x in a1 {
        dict1[x, default: 0] += 1
    }

    for y in a2 {
        if dict1[y] == nil || dict1[y] == 0 {
            result.append(y)
        } else {
            dict1[y]! -= 1
        }
    }

    return result
}

Note that the elements of the arrays have to conform to Hashable in order to use a dictionary. If an element occurs in the second array more than in the first, the extra duplicates are the ones kept. Which is not handled in all other answers

Here are some use cases :

let array1 = [1, 2, 3, 4, 5, 6]
let array2 = [1, 2, 2, 4, 7, 6]

intersect(array1, with: array2) //[2, 7]

struct MyStruct: Hashable { var id: Int }

let array3 = [MyStruct(id: 0), MyStruct(id: 2), MyStruct(id: 3)]
let array4 = [MyStruct(id: 1), MyStruct(id: 2), MyStruct(id: 2)]

intersect(array3, with: array4)  //[{id 1}, {id 2}]

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.