简体   繁体   中英

Adding Array extension for multidimensional arrays in swift?

I have a matrix, ie array of arrays. I want to add some methods to better handle this as extension to Array . I was thinking of writting something like this:

extension Array where Element == Array {
    // my methods
}

But alas, this won't compile, since I have added recursive definition. Obviosly I can omit part where Element == Array , but it seems like nice touch to have these methods show only when appropriate. Is there some other way this can be achieved?

EDIT: as per @Leo Dabus suggestion, I will provide some use case:

I have app that has multiple table view controllers. In each of them I have sections and rows. In order to populate them, I use two arrays: one for section names, and the other one is array of arrays of objects(or structs) -> corresponding sections and rows in index paths. So I want to write methods for manipulation array of arrays based on index path. For example:

a[indexPath] = sender

These objects vary, some are simple strings, some are more complex

Try this one:

extension Array where Element: Collection {
}

To extend an array of arrays of objects (or structs) of type YourType , use this:

extension Array where Element == Array<YourType> { 
    //Your methods
}

You can try this:

// extension primarily for array of arrays
extension Collection where Element: Collection {
    /// all elements (rows) are of the some length
    /// - `[[1,2], [3,4]].allElementsSameLength == true`
    public var allElementsSameLength: Bool {
        guard !isEmpty else { return true }
        return dropFirst().allSatisfy { $0.count == first!.count }
    }
}

run on sample data:

// array of arrays
let data = [
    ["labe", "value", "type"],
    ["name", "joe", "String"],
    ["age", "8", "Int"]
]

let data2 = [
    ["labe", "value", "type"],
    ["name", "joe"],
    ["age", "8", "Int"]
]

let data3 = [[1,1], [3,4]]
let data4 = [[1,2,3]]            // one row only
let data5 = [[Int]]()            // no row

and the result is:

data.allElementsSameLength,     // T
data2.allElementsSameLength,    // F
data3.allElementsSameLength,    // T
data4.allElementsSameLength,    // T
data5.allElementsSameLength,    // T

The solution is to use a Contextual Where Clause on a function, rather than a where on the extension. In a function context you can introduce generic parameters.

Here is an example which computes the trace of a 2D matrix:

public extension Array {
    func trace<T: BinaryFloatingPoint>() -> T where Element == Array<T> {
        var total: T = 0
        
        for i in 0...count {
            let row = self[i]
            total += row[i]
        }
        
        return total
    }
}

However, if you plan to implement 2D arrays, I strongly suggest you consider using a single array of size cols * rows and then indexing it appropriately.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM