In Swift 2, I'm receiving an error:
Cannot convert value of type
'[String:AnyObject]'
to expected argument type'@noescape ([String:AnyObject])'
throws -> Bool"
//today = NSDate()
//array : [[String:AnyObject]]
// I use if let because of we might now get element in the array matching our condition
if let elementOfArray = array.filter({$0["id"] as? Int == anotherDictionary["matchID"] as? Int && ($0["nextFireDate"] as? NSDate)?.compare(today) == NSComparisonResult.OrderedAscending}).first {
let index = array.indexOf(elementOfArray) // error here
}
What I'm doing wrong? I can't understand. :/
My aim, is to find index of that item, I think that I open for alternative solutions, but of course this one is preferred, because I think this is the "right way".
The indexOf
method on Swift arrays does not take an object of a type matching the array's type. Instead, it takes a closure. That closure takes an element of the array's type and returns a bool.
So, in fact, we don't (and shouldn't) even bother with the filter
call unless we actually need the resultant array. If we're just looking for the first object that passes whatever test you are filtering for... well we just pass that exact same test to indexOf
.
So, to keep things simple, if we have an array of strings (and let's say they're all single letter strings with lots of repetition), and I want to find the first index of the string "a"
, rather than filtering the array down to strings that are "a"
, then finding the first string that passed that test with the first
method, and then finding the index of that exact object, instead, I just pass that test into the indexOf
method:
let letters: [String] = ["x", "y", "z", "a", "b", "c"]
let index = letters.indexOf {
$0 == "a"
}
For clarity, it appears that simply passing an individual element and looking for that does work in some cases. It probably relies on conformance to Swift's Equatable
protocol. I could for example have simplied used letters.indexOf("a")
here. The compiler would have been happy. But obviously, not every array is composed required to hold things that conform to Equatable
, and the array can't make assumptions about how to compare its elements then. In these cases, you will have to use the above example of passing a closure. It's probably worth noting that passing this closure to indexOf
rather than first filtering and then calling indexOf
is going to be egregiously more efficient anyway, even if your array allows the letters.indexOf("a")
approach. If for example, I had more complex strings, and I just wanted the first string that started with the letter 'a', this would be far, far more efficient than starting by filtering down the original array to an array of strings starting with 'a'.