Building on this question of mine (and the accepted answer), I want to test containment of a value in an array.
The value is stored in a variable defined as of type Any
, and the array is defined as [Any]
.
The actual types of the value stored in the variable and the elements in the array are decided at runtime, but are guaranteed to satisfy the following conditions:
String
, Int
or Bool
.So far, I got this code working:
var isContained = false
if let intValue = anyValue as? Int {
isContained = arrayOfAny.contains({element in return ((element as? Int) == intValue)})
}
else if let stringValue = anyValue as? String {
isContained = arrayOfAny.contains({element in return ((element as? String) == stringValue)})
}
else if let boolValue = anyValue as? Bool {
isContained = arrayOfAny.contains({element in return ((element as? Bool) == boolValue)})
}
However, there is a lot of logic duplication and I wish I could make it smarter, perhaps something like this:
isContained = arrayOfAny.contains({element in
return ((element as? Equatable) == (anyValue as? Equatable))
})
...but the restrictions on the use of the protocol Equatable
stand in the way. Any advice?
I see now what you are trying to do. Here is an example of how you can make it working
let arrayOfAny:[AnyObject] = [1,7,9,true, "string"]
func getAny(value:AnyObject) -> [AnyObject]{
return self.arrayOfAny.filter ({$0 === value})
}
The above function will return an array of matches which ideally should be a single result or empty array.
Example:
self.getAny(1) // [1]
self.getAny(0) // []
You can also modify it to simply return a Bool
func getAny(value:AnyObject) -> Bool{
return self.arrayOfAny.filter ({$0 === value}).count > 0
}
Example:
self.getAny(1) // true
self.getAny(0) // false
Edit:
As Martin R mentioned this would not always work. Unfortunately I didn't fully tested it before I post this answer. After playing with this for a while I came up with very similar approach to the one NicolasMiari has:
let arrayOfAny:[AnyObject] = [1,Int.max,9,true, "string"]
func getAny(anyValue:AnyObject) -> [AnyObject]{
return self.arrayOfAny.filter ({
var exist:Bool
switch anyValue.self{
case is String: exist = $0 as? String == anyValue as? String
break
case is Int: exist = $0 as? Int == anyValue as? Int
break
case is Bool: exist = $0 as? Bool == anyValue as? Bool
break
default: exist = false
}
return exist
})
}
The downside of this approach is that the int 1
and true
will be returned when calling self.getAny(1)
the result will be [1,1]
as 1
and true
can be successfully casted to both Int
and Bool
and not as probably intended to just return [1]
.
In other words if you just have true
in your array without having Int 1
you will still get positive result as if it was existing in your array. Same works the other way around as well.