用 Swift 進行列表解析及其性能問題
本文寫于 2015.8.15 適用于 Xcode 6 和 Swift 1.2
列表解析可以讓你用更簡潔的方式來創建列表。盡管列表解析沒有在 Swift 的語言指南中提及,但你也可以在 Swift 中實現類似列表解析的一些操作。
如果你想創建一個對元素求平方的列表,像這樣:
var squares = [Int]() for x in 1..<10 { squares.append(x*x) }
在 Python 中,使用列表解析是這樣的:
squares = [x**2 for x in range(10)]
在 Swift 中,你可以這樣做:
let squares = Array(map(1..<10) { $0 * $0 })
對列表中所有元素進行求和你可以這樣做:
var sum = 0 for square in squares { sum = sum + square }
或者使用 reduce 函數
let sum = squares.reduce(0, { $0 + $1 })
對于其它語言中的列表解析,你可以使用任意的序列或者集合作為輸入,而不僅僅是一個區間值。
你可以使用 map/reduce/filter/stride 函數創建你想要的列表類型
列表解析的兩個主要優點是讓代碼變的更簡潔和生成更快的二進制碼。
我剛剛模擬的列表解析看起來很簡潔吧。但我很好奇是否它也能產生更快的二進制碼。
這篇文章 介紹了如何使用 Hopper 來分析 Swift 的匯編代碼,Hopper 是一個 OS X 和 Linux 反編譯程序。 你可以免費使用 Hopper ,不需要付任何費用。
沒有使用列表解析的代碼片段和模擬列表解析的代碼片段都產生了同樣的匯編代碼.
因為兩個代碼片段產生的匯編代碼是一樣的,所以我可以認為它們的執行時間是一樣的。我們可以使用 XCTest 來測試我們程序的執行時間并證明這一點。
測試沒有使用列表解析的代碼片段
func testNoListComprehensionPerformance() { self.measureBlock() { var squares = [Int]() for x in 1...5 { squares.append(x) } } }
相關的輸出是:
Test Case ‘-[speedTestTests.speedTestTests testNoListComprehensionPerformance]’ started.
:0: Test Case ‘-[speedTestTests.speedTestTests testNoListComprehensionPerformance]’ measured [Time, seconds] average: 0.000, relative standard deviation: 236.965%, values: [0.000154, 0.000005, 0.000004, 0.000004, 0.000004, 0.000004, 0.000004, 0.000004, 0.000004, 0.000004], performanceMetricID:com.apple.XCTPerformanceMetric_WallClockTime, baselineName: “”, baselineAverage: , maxPercentRegression: 10.000%, maxPercentRelativeStandardDeviation: 10.000%, maxRegression: 0.100, maxStandardDeviation: 0.100
Test Case ‘-[speedTestTests.speedTestTests testNoListComprehensionPerformance]’ passed (0.262 seconds).
測試模擬列表解析的代碼片段
Test Case ‘-[speedTestTests.speedTestTests testSortaListComprehensionPerformance]’ started.
:0: Test Case ‘-[speedTestTests.speedTestTests testSortaListComprehensionPerformance]’ measured [Time, seconds] average: 0.000, relative standard deviation: 160.077%, values: [0.000045, 0.000005, 0.000004, 0.000003, 0.000003, 0.000003, 0.000003, 0.000004, 0.000003, 0.000003], performanceMetricID:com.apple.XCTPerformanceMetric_WallClockTime, baselineName: “”, baselineAverage: , maxPercentRegression: 10.000%, maxPercentRelativeStandardDeviation: 10.000%, maxRegression: 0.100, maxStandardDeviation: 0.100
Test Case ‘-[speedTestTests.speedTestTests testSortaListComprehensionPerformance]’ passed (0.255 seconds).
他們平均只相差 0.007 秒
我見過最酷的列表解析的應用便是拼寫檢查。Airspeed Velocity 針對 Peter Norvig 的 Python 版本的拼寫檢查 , 改寫了一個 Swift 版本 。
在 Swift 中使用類列表解析的操作的主要優點就是簡潔性。 Paul Graham 寫了一大篇關于在編程語言中簡潔是多么重要的文章。 因為每個程序員每天只能寫一定行數的代碼,如果你以同樣數量的代碼行數完成更多功能,那你每天便可以完成更多的工作任務。這種力量也會讓你重新思考編寫什 么樣的程序是可能的。在一些更繁瑣的語言中,這個拼寫檢查的例子可能就是一個巨大的項目。我喜歡像拼寫檢查這種充滿技術復雜性和神秘感的事物,并且在 Swift 中可以只用幾行代碼便能解決。