Swift 2D阵列通用扩展 - 访问第二维的问题

时间:2016-08-27 09:41:15

标签: arrays swift generics

我正在尝试将以下函数转换为2D数组的通用扩展。

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
}

我特别难以指出如何指定约束以允许我访问第二个维度。这是一次失败的尝试:

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

1 个答案:

答案 0 :(得分:3)

问题在于,编译器并不知道您的扩展是针对2D数组的 - 它只知道它对于集合数组而言。因此,相关类型IndexDistanceIndex不一定是Int

因此,解决方案是限制您的扩展程序,以使Element的{​​{1}} IndexDistanceIndex 类型为Int 。这将允许您形成范围0..<count,因为count现在将是IntIndexDistance)类型 - 您将能够下标{{1}内的元素1}} map(_:) s(因为下标需要Int)。

(支持concrete same-type requirements后执行此操作非常简单,因为您可以简单地将Index约束为Element,但这还不可能。)功能

您还应该注意,您的约束Array是不正确的,因为它会将扩展约束到集合的3D数组(元素是集合的数组,其中该集合的元素是集合)。

最后,您可能需要定义一个Element.Iterator.Element: Collection来代表内部元素&#39; 2D数组的类型,因为Swift目前有some limitations when working with nested types directly,例如在创建该类型的空2D数组时。

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

typealias

使用嵌套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 points out below,因为我们不再需要创建&#39;结果&#,因此无需map(_:) 39;阵列:

typealias

虽然请注意,您的扩展程序限制仅适用于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() } } 索引并非严格必要(但不会产生任何实际差异,因为您只打算将其用于2D数组)。另一种方法是直接遍历内部集合Int

为了做到这一点,您只需要约束您的扩展程序,以便内部集合indices具有与Indices相同类型的Element集合(如果是IndexArrayIndices):

CountableRange<Int>