Let's say I have this array:
let a = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
Now I want something like this:
public func indicesOf(x: Int, array: [[Int]]) -> (Int, Int) {
...
}
so that I can call it like this:
indicesOf(7, array: a) // returns (2, 0)
Of course, I can use:
for i in 0..<array.count {
for j in 0..<array[i].count {
if array[i][j] == x {
return (i, j)
}
}
}
But that is not even close to swifty!
I want a way to do this which is swifty. I think maybe I can use reduce
or map
?
You can simplify your code slightly with enumerate()
and indexOf()
.
Also the function should return an optional tuple because the element
might not be present in the "matrix". Finally, you can make it generic:
func indicesOf<T: Equatable>(x: T, array: [[T]]) -> (Int, Int)? {
for (i, row) in array.enumerate() {
if let j = row.indexOf(x) {
return (i, j)
}
}
return nil
}
You can also make it an extension for a nested Array
of Equatable
elements:
extension Array where Element : CollectionType,
Element.Generator.Element : Equatable, Element.Index == Int {
func indicesOf(x: Element.Generator.Element) -> (Int, Int)? {
for (i, row) in self.enumerate() {
if let j = row.indexOf(x) {
return (i, j)
}
}
return nil
}
}
if let (i, j) = a.indicesOf(7) {
print(i, j)
}
Swift 3:
extension Array where Element : Collection,
Element.Iterator.Element : Equatable, Element.Index == Int {
func indices(of x: Element.Iterator.Element) -> (Int, Int)? {
for (i, row) in self.enumerated() {
if let j = row.index(of: x) {
return (i, j)
}
}
return nil
}
}
Swift 5+
extension Array where Element : Collection,
Element.Iterator.Element : Equatable, Element.Index == Int {
func indicesOf(x: Element.Iterator.Element) -> (Int, Int)? {
for (i, row) in self.enumerated() {
if let j = row.firstIndex(of: x) {
return (i, j)
}
}
return nil
}
}
Version accepting a closure, similar to index(where:), so there it is usable on the array of any elements, not only Equatable
extension Array where Element : Collection, Element.Index == Int {
func indices(where predicate: (Element.Iterator.Element) -> Bool) -> (Int, Int)? {
for (i, row) in self.enumerated() {
if let j = row.index(where: predicate) {
return (i, j)
}
}
return nil
}
}
Use like this:
let testArray = [[1,2,3], [4,5,6], [7,8]]
let testNumber = 6
print(testArray.indices(of: testNumber))
print(testArray.indices{$0 == testNumber})
Optional((1, 2))
Optional((1, 2))
Also, it can be used with IndexPath
:
extension Array where Element : Collection, Element.Index == Int {
func indexPath(where predicate: (Element.Iterator.Element) -> Bool) -> IndexPath? {
for (i, row) in self.enumerated() {
if let j = row.index(where: predicate) {
return IndexPath(indexes: [i, j])
}
}
return nil
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With