-1

Edit: The problem is already solved by @vacawama. But if you are looking for an answer for NSObject classes, you should implement isEqual function which is NSObjectProtocol. Otherwise you gonna get an error says: " Redundant conformance of 'classname' to protocol 'Equatable' "

You can check this for details: Swift 2.2, Contains Method not working


In swift, how can i check if an object is in array?

I have a simple class like this;

class Test: {
    private var _number: Int!
    private var _type: String!

    var number: Int {
            return _number
    }
    var type: String {
            return _type
    }

    init (number: Int, type: String) {
        self._number = number
        self._type = type
    }
}

Also i have this class;

class TestRandom {

    private let _numberArr: [Int] = [1,2,3,4,5,6,7,8,9,10]
    private let _typeArr: [String] = ["x","y","z"]
    public private(set) var _testArr: [Test] = []
    private var _randomTest: Test!

    func randomTestPicker () {
            repeat {

                    let randomNumber = Int(arc4random_uniform(UInt32(self._numberArr.count)))
                    let randomType = Int(arc4random_uniform(UInt32(self._typeArr.count)))

                    self._randomTest = Test(number: self._numberArr[randomNumber], type: self._typeArr[randomType])
            } while self._testArr.contains(_randomTest) 
    }
}

All i want to do is to pick different objects. Lets say i have x2,y4,x6,z3,z8,y2 in _testArr. When i call randomTestPicker, it should not pick x2 or z8. Because they are already in array.

I have tried contains as you see. However it did not work for me. Is there any solution that i can use for this purpose? Or what is the best way to do this?

Edit: I tried self._testArr.contains{$0 === _randomTest} but not working neither.

Community
  • 1
  • 1
Taha
  • 31
  • 8
  • Possible duplicate of [Swift 2 Array Contains object?](http://stackoverflow.com/questions/35443308/swift-2-array-contains-object) – Hamish Feb 05 '17 at 16:09

1 Answers1

3

You can't use contains that way since your class doesn't conform to the Equatable protocol.

Add :Equatable to your class definition and implement the == function which compares two of your objects:

class Test: Equatable {
    private var _number: Int!
    private var _type: String!

    var number: Int {
        return _number
    }
    var type: String {
        return _type
    }

    init (number: Int, type: String) {
        self._number = number
        self._type = type
    }
}

func ==(lhs: Test, rhs: Test) -> Bool {
    return lhs.number == rhs.number && lhs.type == rhs.type
}

The other way this could have been done is to use the predicate form of contains. The predicate takes two objects and returns a Bool indicating if they match. In that case, you would write:

self._testArr.contains { $0.number == _randomTest.number && $0.type == _randomTest.type }

As you can see, in this case the closure is essentially the == function from above, so implementing the Equatable protocol is the cleaner way to do it.

The closure { $0 === _randomTest } doesn't work because that only tests if the objects are the same instance. In your case, you need to check if the two objects have the same properties, and you are not interested if they are same instance. The way you are creating the objects, you never would create an instance that is already in the array, so this check would always return false.

vacawama
  • 150,663
  • 30
  • 266
  • 294