2D数组扩展Swift 3.1.1

Ste*_*nov 5 arrays multidimensional-array swift swift3

我试图Array在Swift 3.1.1中进行扩展,该扩展支持将对象添加到2D数组中的某个索引,即使该数组尚未填充.扩展还应该提供获取对象的能力indexPath.我在Swift 2中有这个代码,但我似乎无法将它迁移到Swift 3.这是Swift 2代码:

extension Array where Element: _ArrayProtocol, Element.Iterator.Element: Any {

    mutating func addObject(_ anObject : Element.Iterator.Element, toSubarrayAtIndex idx : Int) {
        while self.count <= idx {
            let newSubArray = Element()
            self.append(newSubArray) 
        }

        var subArray = self[idx]
        subArray.append(anObject)
    }

    func objectAtIndexPath(_ indexPath: IndexPath) -> Any {
        let subArray = self[indexPath.section]
        return subArray[indexPath.row] as Element.Iterator.Element
    }
}
Run Code Online (Sandbox Code Playgroud)

代码来自这个答案.

Ham*_*ish 5

正如马丁说,在这里他的答案,_ArrayProtocol 不再public在雨燕3.1,因此这意味着你可以不使用它作为您的扩展的约束.

在您的情况下,一个简单的替代方法是将Array's 限制ElementRangeReplaceableCollection- 它既定义了一个init()需要"空集合" 的需求,又将一个append(_:)方法限制为集合中的元素.

extension Array where Element : RangeReplaceableCollection {

    typealias InnerCollection = Element
    typealias InnerElement = InnerCollection.Iterator.Element

    mutating func fillingAppend(
        _ newElement: InnerElement,
        toSubCollectionAtIndex index: Index) {

        if index >= count {
            append(contentsOf: repeatElement(InnerCollection(), count: index + 1 - count))
        }

        self[index].append(newElement)
    }
}
Run Code Online (Sandbox Code Playgroud)

另请注意,我们将附加作为单个调用(使用append(contentsOf:)执行,确保我们只需要调整外部数组的大小一次.

为了从给定的方法来获取一个元素IndexPath,你可以约束内部元件类型是一个Collection具有Int Index:

// could also make this an extension on Collection where the outer Index is also an Int.
extension Array where Element : Collection, Element.Index == Int {

    subscript(indexPath indexPath: IndexPath) -> Element.Iterator.Element {
        return self[indexPath.section][indexPath.row]
    }
}
Run Code Online (Sandbox Code Playgroud)

请注意,我认为它subscript不是一种方法,因为我认为它更符合ArrayAPI.

你现在可以简单地使用这些扩展:

var arr = [[Int]]()

arr.fillingAppend(6, toSubCollectionAtIndex: 3)
print(arr) // [[], [], [], [6]]

let indexPath = IndexPath(row: 0, section: 3)
print(arr[indexPath: indexPath]) // 6
Run Code Online (Sandbox Code Playgroud)

虽然当然如果您事先知道外部数组的大小,该fillingAppend(_:toSubCollectionAtIndex:)方法是多余的,因为您可以通过以下方式创建嵌套数组:

var arr = [[Int]](repeating: [], count: 5)
Run Code Online (Sandbox Code Playgroud)

这将创建一个[[Int]]包含5个空[Int]元素的数组.