Swift 2D Array Generic Extension - 访问第二维的问题 [英] Swift 2D Array Generic Extension - issue accessing 2nd dimension

查看:16
本文介绍了Swift 2D Array Generic Extension - 访问第二维的问题的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试将以下函数转换为二维数组的通用扩展.

I'm trying to transform the following function into a generic extension for 2D Arrays.

func rotate(_ input: [[Int]]) -> [[Int]]
{
  let length = input[0].count
  var value = Array(repeating: [Int](), count: length)
  for index in 0 ..< length
  {
    value[index] = input.map { $0[index] }.reversed()
  }
  return value
}

对于如何指定约束以允许我访问第二维,我特别困惑.这是一次失败的尝试:

I'm specifically stumped as to how to specify the constraints to allow me to access the second dimension. Here's a failed attempt:

extension Array where Element: Collection, Element.Iterator.Element: Collection
{
  private func rotate()
  {
    let count = self[0].count // Element.IndexDistance instead of Int

    // Expression type 'Array<Element>' is ambiguous without more context
    var returnValue = Array(repeating: Element, count: 11)
    for index in 0 ..< count // Element.IndexDistance instead of Int
    {
      returnValue[index] = self.map { $0[index] }.reversed()
    }
    return returnValue
  }
}

推荐答案

问题是编译器不知道您的扩展是针对 2D 数组的——它只知道它是针对集合数组的.因此,关联类型 IndexDistanceIndex 不一定是 Int.

The problem is that the compiler doesn't know that your extension is for 2D arrays – it just knows that it's for arrays of collections. Therefore the associated types IndexDistance and Index aren't necessarily Int.

因此,解决方案是限制您的扩展,以便 ElementIndexDistanceIndex 输入 Int.这将使您形成范围 0..,因为 count 现在将属于 Int (IndexDistancecode>) – 您将能够使用 Ints 为 map(_:) 中的元素添加下标(因为下标需要一个 Index>).

The solution therefore is to constrain your extension so that the Element's IndexDistance and Index are of type Int. This will let you form the range 0..<count, as count will now be of type Int (IndexDistance) – and you will be able to subscript the elements within the map(_:) with Ints (as the subscript expects an Index).

(这将是微不足道的一次 具体的相同类型要求 被支持,因为您可以简单地将Element 限制为一个Array,但这尚不可能.)

(This will be trivial to do once concrete same-type requirements are supported, as you could simply constrain the Element to be an Array, however this is not yet possible.)

您还应该注意您的约束 Element.Iterator.Element: Collection 是不正确的,因为这会将扩展限制为集合的 3D 数组(元素是集合的数组,其中该集合的元素是一个集合).

You should also note that your constraint Element.Iterator.Element: Collection is incorrect, as that'll constrain the extension to 3D arrays of collections (An array where the element is a collection, where the elements of that collection are a collection).

最后,您可能需要定义一个 typealias 来表示二维数组的内部元素"类型,因为 Swift 目前有 直接使用嵌套类型时的一些限制,例如创建该类型的空二维数组时.

Finally, you may have to define a typealias to represent the 'inner element' type of the 2D array, as Swift currently has some limitations when working with nested types directly, for example when creating an empty 2D array of that type.

因此,您当前方法的工作版本将如下所示:

Therefore, a working version of your current method would look something like this:

extension Array where Element: Collection, Element.Index == Int, Element.IndexDistance == Int {

    private func rotate() -> [[Element.Iterator.Element]] {

        typealias InnerElement = Element.Iterator.Element

        // in the case of an empty array, simply return an empty array
        if self.isEmpty { return [] } 
        let length = self[0].count

        var returnValue = [[InnerElement]](repeating: [InnerElement](), count: length)
        for index in 0..<length {
            returnValue[index] = self.map{ $0[index] }.reversed()
        }
        return returnValue
    }
}

正如 @MartinR 在下面指出的那样,可以通过使用嵌套的 map(_:) 大大简化,消除对 typealias 的需要,因为我们不再需要创建结果"数组:

Which, as @MartinR points out below, could be simplified considerably by using a nested map(_:), eliminating the need of a typealias as we no longer need to create a 'result' array:

private func rotate() -> [[Element.Iterator.Element]] {

    if self.isEmpty { return [] }
    let length = self[0].count

    return (0..<length).map { index in
        self.map { $0[index] }.reversed()
    }
}

<小时>

尽管请注意,将扩展限制为仅使用 Int 索引并不是绝对必要的(但是没有实际区别,因为您只打算将其与 2D 数组一起使用).另一种选择是直接迭代内部集合的indices.


Although note that the constraining of your extension to only work with Int indices isn't strictly necessary (however makes no practical difference as you're only intending to use this with 2D arrays). Another alternative is to just iterate directly over the inner collection's indices.

为了做到这一点,你只需要限制你的扩展,以便内部集合的Indices具有与Index<相同类型的Element集合的/code>(在 Array 的情况下,IndicesCountableRange):

In order to do this, you simply have to constrain your extension so that the inner collection's Indices have Elements of the same type as the Index of the collection (in the case of an Array, Indices is a CountableRange<Int>):

extension Array where Element: Collection, Element.Indices.Iterator.Element == Element.Index {
    private func rotate() -> [[Element.Iterator.Element]] {

        if self.isEmpty { return [] }

        return self[0].indices.map { index in
            self.map { $0[index] }.reversed()
        }
    }
}

这篇关于Swift 2D Array Generic Extension - 访问第二维的问题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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