Noah Wilder
Noah Wilder

Reputation: 1574

Extending Arrays of Arrays - Swift 4.1

Extend Arrays of Arrays

Swift 4.1, Xcode 9.3

How do I extend Array<Array> in Swift?

extension Array where Element == Array { //This is where the error occurs
    someMethod()
}

Furthermore, how would I extend an array of arrays of a specific type, for example:

extension Array where Element == Array<Int> { //Can I even do this?
    someOtherMethod()
}

Thanks in advance for your help!

Upvotes: 5

Views: 1652

Answers (4)

Palli
Palli

Reputation: 680

Solution for generic approach (Swift 5.5):

extension Collection where Element: Collection, Element.Element: Equatable, Element.Index == Int {

    // Returns aggregated count of all elements.
    func totalCount() -> Int {
        return reduce(into: 0) { partialResult, innerCollection in
            partialResult += innerCollection.count
        }
    }

    // Returns `IndexPath` for given `element` inside 2d array.
    func indexPath(for element: Element.Element) -> IndexPath? {
        for (section, innerCollection) in enumerated() {
            if let row = innerCollection.firstIndex(of: element) {
                return IndexPath(row: row, section: section)
            }
        }
        
        return nil
    }
}

Upvotes: 0

Porter Child
Porter Child

Reputation: 152

Here's a start for someone wanting to do this more generically than the answers so far have shown.

Extending Array<Array>:

protocol ExpressibleAsDouble { // for illustration
    func asDouble() -> Double
}

extension Array where Element: Sequence, Element.Element: ExpressibleAsDouble {
    func asDoubles() -> [[Double]] {
        return self.map { row in
            row.map { scalar in
                scalar.asDouble()
            }
        }
    }
}

//-------------------------------------------
//example usage
extension Int: ExpressibleAsDouble {
    func asDouble() -> Double {
        return Double(self)
    }
}

let ints: [[Int]] = [[1, 2], [3, 4]]
print(ints.asDoubles())
// prints: [[1.0, 2.0], [3.0, 4.0]]

This is actually extending Array<any sequence, Array being one possible option>, I'm not sure if you can constrict it to just Array<Array> if you want to refer to the nested scalars generically.

Element refers to the first dimension of the Array (which is another Array), and Element.Element refers to the type of the nested dimension (which are scalars if we're talking about a 2D array).

Upvotes: 0

Kamran
Kamran

Reputation: 15248

You can extend in either way

extension Array where Element == Int {

    func someIntegers() {

    }
}

extension Array where Element == Array<String> {

    func someStrings() {

    }
}

and call like this anywhere,

[0, 1, 2].someIntegers()

[["hi"]].someStrings()

Upvotes: 5

Gereon
Gereon

Reputation: 17863

I've used

extension Array where Element: RandomAccessCollection, Element.Index == Int {
}

e.g. to add custom subscripts by IndexPath

Upvotes: 2

Related Questions