Array 有一个初始化器 (init(_:)),它可以从任何 Sequence 生成 Array,例如 ArraySlice。但是,使用它会强制复制数组数据,这使得像这样的简单求和算法实际上具有O(nums.count^2) 的性能,即使它看起来只扫描数组一次。
func sum(_ nums: [Int]) -> Int {
guard let head = nums.first else { return 0 } //base case, empty list.
return head + sum(Array(nums.dropFirst()))
}
let input = Array(1...10)
let output = sum(input)
print(output)
为了解决这个问题,一个更好的实现将改为仅在 ArraySlices 上运行,允许无副本切片,但这需要首先将输入 Array 转换为 ArraySlice。幸运的是,内部函数可以帮助使这对公共 API 透明,但它确实使代码更长。
func sum(_ nums: [Int]) -> Int {
func sum(_ nums: ArraySlice<Int>) -> Int {
guard let head = nums.first else { return 0 } //base case, empty list.
return head + sum(nums.dropFirst())
}
return sum(ArraySlice(nums))
}
但真的,正如matt 所说,不要这样做。编程的头/尾方法在一种通过模式匹配、良好的编译器优化、尾调用优化等很好地促进它的语言中是有意义的。Swift 的设计鼓励使用reduce。它不仅更短、更易读,而且性能也更高。
作为比较,以下是典型的 Swift 方法:
extension Sequence where Iterator.Element: Integer {
func sum() -> Iterator.Element {
return self.reduce(0, +)
}
}
- 它更简单、更短。
- 它是多态的,所以它适用于任何
Sequence,而不是仅限于Array
-
它对任何Integer 类型都是通用的,而不仅仅是Int。所以这些都有效:
print(Array<UInt >(1...10).sum())
print(Array<UInt8 >(1...10).sum())
print(Array<UInt16>(1...10).sum())
print(Array<UInt32>(1...10).sum())
print(Array<UInt64>(1...10).sum())
print(Array< Int >(1...10).sum())
print(Array< Int8 >(1...10).sum())
print(Array< Int16>(1...10).sum())
print(Array< Int32>(1...10).sum())
print(Array< Int64>(1...10).sum())
但是,如果您坚持采用这种头/尾方法,您可以尝试以下两种技术之一:
extension Collection {
func headTail1<Head, Tail, ReturnType>(_ closure: (Head?, Tail) -> ReturnType) -> ReturnType
where Head == Self.Element, Tail == Self.SubSequence {
return closure(self.first, self.dropFirst())
}
func headTail2<Head, Tail>() ->(Head?, Tail)
where Head == Self.Element, Tail == Self.SubSequence {
return (self.first, self.dropFirst())
}
}
func sum1<C: Collection, I: Numeric>(_ nums: C) -> I
where C.Element == I {
return nums.headTail1 { head, tail in
guard let head = head else { return 0 } //base case, empty list
return head + sum(tail)
}
}
func sum2<C: Collection, I: Numeric>(_ nums: C) -> I
where C.Element == I {
let (_head, tail) = nums.headTail2()
guard let head = _head else { return 0 } //base case, empty list
return head + sum(tail)
}
print(sum(Array(1...10)))
此代码抽象出列表如何拆分为头部和尾部的细节,让您只需担心为您提供的head 和tail 即可编写sum。