Swift 4.2 中的快速数组比较
Fast Array comparison in Swift 4.2
我有两个包含 11059200 个元素的整数数组。从下面的例子中,
我正在通过比较 d2
中的元素索引将数组 d1
的值更改为 0
以下程序的计算时间为
Comparing started: 2019-03-02 08:45:56 +0000
Comparing finished: 2019-03-02 08:46:00 +0000
这个过程用了 4 秒是更多的时间。
我想减少时间。有没有可能?谢谢
var d1 = [Int]()
var d2 = [Int]()
let value = 11059200
for _ in 0...value{
d1.append(Int.random(in: 0...value))
d2.append(Int.random(in: 0...value))
}
print("Comparing started: \(Date())")
var _ = d1.enumerated().compactMap { (index,value) -> Int in
return d2[index] == value ? 0 : value
}
print("Comparing finished: \(Date())")
更新:
根据 Alexander 的评论,我正在使用地图将时间从 2-3 秒减少
var _ = d1.enumerated().map { (index,value) -> Int in
return d2[index] == value ? 0 : value
}
您可能可以通过使用简单的地图而不是 compactMap 来加快速度。您没有返回可选(某种),因此您无需使用 compactMap。事实上,你的表达 d2[index] == value ? 0 : value 被隐式提升为 optional,只是为了 compactMap 然后必须花时间展开它。
此外,您可以使用 zip
将 2 个序列迭代在一起来简化代码:
import Foundation
func printTimeElapsedWhenRunningCode(title: String, operation: () -> Void) {
let startTime = CFAbsoluteTimeGetCurrent()
operation()
let timeElapsed = CFAbsoluteTimeGetCurrent() - startTime
print("Time elapsed for \(title): \(timeElapsed) s.")
}
let max = 11059200
let d1 = (0...max).map { _ in Int.random(in: 0...max) }
let d2 = (0...max).map { _ in Int.random(in: 0...max) }
printTimeElapsedWhenRunningCode(title: "Enumerating and indexing, comparing using compactMap (original)") {
let result = d1.enumerated().compactMap { index, value -> Int in
return d2[index] == value ? 0 : value
}
print(result.count)
}
printTimeElapsedWhenRunningCode(title: "Enumerating and indexing, comparing using map") {
let result = d1.enumerated().map { index, value -> Int in
return d2[index] == value ? 0 : value
}
print(result.count)
}
// just for a benchmark, don't write codel like this.
printTimeElapsedWhenRunningCode(title: "Manual Indexing") {
var result = Array<Int>()
result.reserveCapacity(d1.count)
for i in d1.indices {
let (d1Value, d2Value) = (d1[i], d2[i])
let newValue = d1Value == d2Value ? 0 : d1Value
result.append(newValue)
}
print(result.count)
}
// "Best" from a readibility stand-point
printTimeElapsedWhenRunningCode(title: "Zip") {
let result = zip(d1, d2).map { d1Value, d2Value in
return d1Value == d2Value ? 0 : d1Value
}
print(result.count)
}
这是在未优化构建中的初步结果。这些完全没有意义。调试构建的目标是让编译器在尽可能短的时间内生成正确的、可运行的程序,而对性能的关注绝对为 0。对于快速开发迭代很有用,但是对于bench marking没用。
Time elapsed for Enumerating and indexing, comparing using compactMap (original): 6.206556916236877 s.
Time elapsed for Manual Indexing: 0.3380240201950073 s.
Time elapsed for Zip: 7.123739957809448 s.
Time elapsed for Enumerating and indexing, comparing using map: 5.2529460191726685 s.
当您打开优化(swiftc
cli 中的 -O
标志,或作为 Xcode 构建目标中的一个选项)时,您会得到一个完全不同的画面:
Time elapsed for Enumerating and indexing, comparing using compactMap (original): 0.5904990434646606 s.
Time elapsed for Enumerating and indexing, comparing using map: 0.22207605838775635 s.
Time elapsed for Manual Indexing: 0.18644499778747559 s.
Time elapsed for Zip: 0.2339940071105957 s.
我会推荐基于 zip
的方法,因为它的可读性。如果性能 绝对 至关重要,以至于您确定可以为了微小的速度优势牺牲可读性和可维护性,那么切换到手动索引可能是值得的,但那是不太可能是这种情况。
我有两个包含 11059200 个元素的整数数组。从下面的例子中,
我正在通过比较 d2
d1
的值更改为 0
以下程序的计算时间为
Comparing started: 2019-03-02 08:45:56 +0000
Comparing finished: 2019-03-02 08:46:00 +0000
这个过程用了 4 秒是更多的时间。
我想减少时间。有没有可能?谢谢
var d1 = [Int]()
var d2 = [Int]()
let value = 11059200
for _ in 0...value{
d1.append(Int.random(in: 0...value))
d2.append(Int.random(in: 0...value))
}
print("Comparing started: \(Date())")
var _ = d1.enumerated().compactMap { (index,value) -> Int in
return d2[index] == value ? 0 : value
}
print("Comparing finished: \(Date())")
更新:
根据 Alexander 的评论,我正在使用地图将时间从 2-3 秒减少
var _ = d1.enumerated().map { (index,value) -> Int in
return d2[index] == value ? 0 : value
}
您可能可以通过使用简单的地图而不是 compactMap 来加快速度。您没有返回可选(某种),因此您无需使用 compactMap。事实上,你的表达 d2[index] == value ? 0 : value 被隐式提升为 optional,只是为了 compactMap 然后必须花时间展开它。
此外,您可以使用 zip
将 2 个序列迭代在一起来简化代码:
import Foundation
func printTimeElapsedWhenRunningCode(title: String, operation: () -> Void) {
let startTime = CFAbsoluteTimeGetCurrent()
operation()
let timeElapsed = CFAbsoluteTimeGetCurrent() - startTime
print("Time elapsed for \(title): \(timeElapsed) s.")
}
let max = 11059200
let d1 = (0...max).map { _ in Int.random(in: 0...max) }
let d2 = (0...max).map { _ in Int.random(in: 0...max) }
printTimeElapsedWhenRunningCode(title: "Enumerating and indexing, comparing using compactMap (original)") {
let result = d1.enumerated().compactMap { index, value -> Int in
return d2[index] == value ? 0 : value
}
print(result.count)
}
printTimeElapsedWhenRunningCode(title: "Enumerating and indexing, comparing using map") {
let result = d1.enumerated().map { index, value -> Int in
return d2[index] == value ? 0 : value
}
print(result.count)
}
// just for a benchmark, don't write codel like this.
printTimeElapsedWhenRunningCode(title: "Manual Indexing") {
var result = Array<Int>()
result.reserveCapacity(d1.count)
for i in d1.indices {
let (d1Value, d2Value) = (d1[i], d2[i])
let newValue = d1Value == d2Value ? 0 : d1Value
result.append(newValue)
}
print(result.count)
}
// "Best" from a readibility stand-point
printTimeElapsedWhenRunningCode(title: "Zip") {
let result = zip(d1, d2).map { d1Value, d2Value in
return d1Value == d2Value ? 0 : d1Value
}
print(result.count)
}
这是在未优化构建中的初步结果。这些完全没有意义。调试构建的目标是让编译器在尽可能短的时间内生成正确的、可运行的程序,而对性能的关注绝对为 0。对于快速开发迭代很有用,但是对于bench marking没用。
Time elapsed for Enumerating and indexing, comparing using compactMap (original): 6.206556916236877 s.
Time elapsed for Manual Indexing: 0.3380240201950073 s.
Time elapsed for Zip: 7.123739957809448 s.
Time elapsed for Enumerating and indexing, comparing using map: 5.2529460191726685 s.
当您打开优化(swiftc
cli 中的 -O
标志,或作为 Xcode 构建目标中的一个选项)时,您会得到一个完全不同的画面:
Time elapsed for Enumerating and indexing, comparing using compactMap (original): 0.5904990434646606 s.
Time elapsed for Enumerating and indexing, comparing using map: 0.22207605838775635 s.
Time elapsed for Manual Indexing: 0.18644499778747559 s.
Time elapsed for Zip: 0.2339940071105957 s.
我会推荐基于 zip
的方法,因为它的可读性。如果性能 绝对 至关重要,以至于您确定可以为了微小的速度优势牺牲可读性和可维护性,那么切换到手动索引可能是值得的,但那是不太可能是这种情况。