So I’m in the middle of trying to create a function that allows you to look up any element on an array. And this is where I’ve more or less hit a brick wall. This is the starting point function. Update: scroll down for more
extension Array { func indexOfElement<T:Equatable>(sought:T) -> Int? { for i in 0..self.count { if ((self[i] as? T) == sought) { return i } } return nil } }
It works pretty well on all the following examples, letting me search through arrays regardless of parameter type.
let abc = ["a", "b", "c"] abc.indexOfElement(77) abc.indexOfElement("c") let a01 = [0, 1, 5, 3, 9] a01.indexOfElement(5) a01.indexOfElement(99) a01.indexOfElement("hello")
Here’s where it gets ugly. When I create an array with mixed elements, it completely fails. All of these test cases return nil.
// Miserable failure let a02 : Array = [0, 1, "HELLO", 3, 9] a02.indexOfElement("Cow") a02.indexOfElement(9) a02.indexOfElement("HELLO")
If you have any insight on what’s going wrong, I’d love to hear about it. The best I can figure at this point is that the a02 array is forced to be an NSArray rather than an Array, but I’m not sure of the details.
UPDATE: So after a bit of slogging, I confirmed that the mixed elements default to an NSArray. Adding an NSArray extension fixed the problem as you see below. Thanks everyone who commented, responded to me on Twitter, and in IRC.
import Foundation let array1 = [1, 2, 3, 4, 5] let array2 = ["a", "b", "c", "d"] let array3 = [1, 2, "a"] let array4 = array3 as AnyObject[] // don't try to force this // Oh this is interesting. They look different println(array1) println(array2) println(array3) // 3 appears to be an NSArray of some kind println(array3 as NSArray) println(array2 as NSArray) // In addition to extension Array { func indexOfElement(item:T) -> Int? { for i in 0..self.count { if ((self[i] as? T) == item) { return i } } return nil } } // Just add this extension NSArray { func indexOfElement(item : AnyObject?) -> Int? { return self.indexOfObject(item) } } // And now these all work array2.indexOfElement("c") array2.indexOfElement(2) array2.indexOfElement("d") array3.indexOfElement(2) array3.indexOfElement(1) array3.indexOfElement("a") // Just avoid doing stuff with array 4
5 Comments
I think Apple had mentioned something about putting different types of objects in an array in Swift. They said if you were going to do that you might as well just use a dictionary because arrays are only supposed to be used for one type of object.
What if you made the type of a02 AnyObject?
From the Swift Book:
“Arrays store ordered lists of values of the same type. Dictionaries store unordered collections of values of the same type”
So i guess that collections from different types are not an ok thing to do?
Updating now, but yes, the problem is that it (currently) automatically creates an NSArray from mixed items
Probably you know this, but there is also the built in function “find”, which will work for anything conforming to the Collection protocol, which the Swift Arrays does. It returns an optional value with the index of the element.
let v = [1,2,3,100,5]
find(v,100)
The signature of find is at line 4338 in the Swift kit source listing.
But this won’t handle heterogenous arrays, because Swift won’t, I think.