2D数组扩展Swift 3.1.1 [英] 2D Array extension Swift 3.1.1

查看:71
本文介绍了2D数组扩展Swift 3.1.1的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试在Swift 3.1.1中进行 Array 扩展,以支持将对象添加到2D Array中的特定索引,即使未填充该数组也是如此还.该扩展还应该提供在特定 indexPath 处获取对象的功能.我在Swift 2中有此代码,但似乎无法将其迁移到Swift3.这是Swift 2代码:

I am trying to make an Array extension in Swift 3.1.1 that supports the addition of an object to a certain index in a 2D Array even if the array hasn't been populated yet. The extension should also provide the ability to get an object at certain indexPath. I have the code for this in Swift 2 but I don't seem to be able to migrate it to Swift 3. This is the Swift 2 code:

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
    }
}

此代码来自此 answer .

推荐答案

正如马丁在此处的回答中所述 ,<代码> _ArrayProtocol 在Swift 3.1中不再是 public ,因此,您不能将其用作扩展中的约束.

As Martin says in his answer here, _ArrayProtocol is no longer public in Swift 3.1, therefore meaning that you cannot use it as a constraint in your extension.

在您的情况下,一个简单的替代方法是将 Array Element 约束为 append(_:)方法,以便将元素添加到集合中.

A simple alternative in your case is to instead constrain the Array's Element to being a RangeReplaceableCollection – which both defines an init() requirement meaning "empty collection", and an append(_:) method in order to add elements to the collection.

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)
    }
}

还请注意,我们将添加作为单个调用进行(使用 append(contentsOf:)),以确保我们最多只需要调整外部数组的大小.

Note also that we're doing the append as a single call (using append(contentsOf:), ensuring that we only have to resize the outer array at most once.

要使您的方法从给定的 IndexPath 中获取元素,只需将内部元素类型限制为

For your method to get an element from a given IndexPath, you can just constrain the inner element type to being a Collection with an 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]
    }
}

请注意,我将其设为 subscript 而不是方法,因为我觉得它更适合 Array 的API.

Note that I've made it a subscript rather than a method, as I feel it fits better with Array's API.

您现在可以像这样简单地使用这些扩展名:

You can now simply use these extensions like so:

var arr = [[Int]]()

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

let indexPath = IndexPath(row: 0, section: 3)
print(arr[indexPath: indexPath]) // 6

当然,如果您事先知道外部数组的大小,则 fillingAppend(_:toSubCollectionAtIndex:)方法是多余的,因为您可以这样说来创建嵌套数组:

Although of course if you know the size of the outer array in advance, the fillingAppend(_:toSubCollectionAtIndex:) method is redundant, as you can just create your nested array by saying:

var arr = [[Int]](repeating: [], count: 5)

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

which will create an [[Int]] array containing 5 empty [Int] elements.

这篇关于2D数组扩展Swift 3.1.1的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆