給swift程式猿留下深刻印象的10個Swift代碼,swift印象10代碼
通過使用單行程式碼完成同樣的 10 個練習,我們來看看 Swift 和其他語言之間的較量。
將數組中每個元素的值乘以 2
使用map來實現
var arr = [1,2,3,4]; var newArr = arr.map{$0*2} for item in newArr { print(item) }
代碼簡單明了地完成了數組元素乘2
求一組數位和
這個問題可以通過使用 reduce
方法和加號運算子解決,這是因為加號運算子實際上也是一個函數。不過這個解法是非常顯而易見的,待會兒我們會看到 reduce
方法更具有創造力的使用。
var arr = [1,2,3,4]; let sum = arr.reduce(0, combine: +) print(sum)
檢索字串中含有某個單詞
我們使用 contains方法判斷一個字串中是否至少含有一個被選中的關鍵字:
let arr = ["ForrestWoo","Swift1"] let str = "My name is ForrestWoo,I am learning Swift" let query = arr.contains(str.containsString) print(query)
讀取一個檔案
let path = NSBundle.mainBundle().pathForResource("filter", ofType: "rtf")
let lines = try? String(contentsOfFile: path!).characters.split{$0 == "\n"}.map(String.init)
for item in lines! {
print(item)
}
祝你生日快樂
let name = "Forrest" (1...4).forEach{print("Happy Birthday " + (($0 == 3) ? "dear \(name)":"to You"))}
這段代碼會將“祝你生日快樂”這首歌的歌詞輸出到控制台中,它在一段區間內簡單的使用了 map
函數,同時也用到了三元運算子。
數組過濾
假設我們需要使用一個給定的過濾函數將一個序列(sequence)分割為兩部分。很多語言除了有常規的map
,flatMap
,reduce
,filter
等函數外,還有一個 partitionBy
函數恰好可以完成這個需求。正如你所知,Swift 沒有類似的函數(我們不想在這裡使用 NSArray 中的函數,並通過NSPredicate 實現過濾功能)。
所以,我們可以通過拓展 SequenceType
,並為它添加 partitionBy
函數來解決這個問題。我們使用這個函數將整數數組分割為兩部分:
extension SequenceType{ typealias Element = Self.Generator.Element func partitionBy(fu: (Element)->Bool)->([Element],[Element]){ var first=[Element]() var second=[Element]() for el in self { if fu(el) { first.append(el) }else{ second.append(el) } } return (first,second) }} let part = [82, 58, 76, 49, 88, 90].partitionBy{$0 < 60}part // ([58, 49], [82, 76, 88, 90])
實際上,這不是單行代碼,而且使用了命令式的解法。能不能使用 filter
對它略作改進呢?
extension SequenceType{ func anotherPartitionBy(fu: (Self.Generator.Element)->Bool)->([Self.Generator.Element],[Self.Generator.Element]){ return (self.filter(fu),self.filter({!fu($0)})) }} let part2 = [82, 58, 76, 49, 88, 90].anotherPartitionBy{$0 < 60}part2 // ([58, 49], [82, 76, 88, 90])
這種解法略好一些,但是他遍曆了序列兩次。而且為了用單行代碼實現,我們刪除了閉合函數,這會導致很多重複的內容(過濾函數和數組會在兩處被用到)。
能不能只用單個資料流就對原來的序列進行轉換,把兩個部分分別存入一個元組中呢?答案是是可以的,使用 reduce
方法:
var part3 = [82, 58, 76, 49, 88, 90].reduce( ([],[]), combine: { (a:([Int],[Int]),n:Int) -> ([Int],[Int]) in (n<60) ? (a.0+[n],a.1) : (a.0,a.1+[n]) })part3 // ([58, 49], [82, 76, 88, 90])
這裡我們建立了一個用於儲存結果的元組,它包含兩個部分。然後依次取出原來序列中的元素,根據過濾結果將它放到第一個或第二個部分中。
我們終於用真正的單行代碼解決了這個問題。不過有一點需要注意,我們使用 append
方法來構造兩個部分的數組,所以這實際上比前兩種實現慢一些。
擷取並解析 XML 格式的網路服務
上述的某些語言不需要依賴外部的庫,而且預設有不止一種方案可以處理 XML 格式的資料(比如 Scala 自身就可以將 XML 解析成對象,儘管實現方法比較笨拙),但是 (Swift 的)Foundation 庫僅提供了 SAX 解析器,叫做 NSXMLParser。你也許已經猜到了:我們不打算使用這個。
在這種情況下,我們可以選擇一些開源的庫。這些庫有的用 C 實現,有的用 Objective-C 實現,還有的是純 Swift 實現。
這次,我們打算使用純 Swift 實現的庫:AEXML:
let xmlDoc = try? AEXMLDocument(xmlData: NSData(contentsOfURL: NSURL(string:"https://www.ibiblio.org/xml/examples/shakespeare/hen_v.xml")!)!) if let xmlDoc=xmlDoc { var prologue = xmlDoc.root.children[6]["PROLOGUE"]["SPEECH"] prologue.children[1].stringValue // Now all the youth of England are on fire, prologue.children[2].stringValue // And silken dalliance in the wardrobe lies: prologue.children[3].stringValue // Now thrive the armourers, and honour's thought prologue.children[4].stringValue // Reigns solely in the breast of every man: prologue.children[5].stringValue // They sell the pasture now to buy the horse,}
找到數組中最小(或最大)的元素
我們有多種方式求出 sequence 中的最大和最小值,其中一種方式是使用 minElement
和maxElement
函數:
//Find the minimum of an array of Ints[10,-22,753,55,137,-1,-279,1034,77].sort().first[10,-22,753,55,137,-1,-279,1034,77].reduce(Int.max, combine: min)[10,-22,753,55,137,-1,-279,1034,77].minElement() //Find the maximum of an array of Ints[10,-22,753,55,137,-1,-279,1034,77].sort().last[10,-22,753,55,137,-1,-279,1034,77].reduce(Int.min, combine: max)[10,-22,753,55,137,-1,-279,1034,77].maxElement()
平行處理
某些語言支援用簡單透明的方式允許對序列的平行處理,比如使用 map
和 flatMap
這樣的函數。這使用了底層的線程池,可以加速多個依次執行但又彼此獨立的操作。
Swift 還不具備這樣的特性,但我們可以用 GCD 實現:
http://moreindirection.blogspot.it/2015/07/gcd-and-parallel-collections-in-swift.html
埃拉托色尼選篩法
古老而優秀的埃拉托色尼選篩法被用於找到所有小於給定的上限 n 的質數。
首先將所有小於 n 的整數都放入一個序列(sequence)中,這個演算法會移除每個數位倍數,直到剩下的所有數字都是質數。為了加快執行速度,我們其實不必檢查每一個數位倍數,當檢查到 n 的平方根時就可以停止。
基於以上定義,最初的實現可能是這樣的:
var n = 50var primes = Set(2...n) (2...Int(sqrt(Double(n)))).forEach{primes.subtractInPlace((2*$0).stride(through:n, by:$0))}primes.sort()
在外層的區間裡,我們遍曆每一個需要檢查的數字。對於每一個數字,我們使用stride(through:Int by:Int)
Function Compute出由它的倍數構成的序列。最初,我們用所有 2 到 n 的整數構造了一個集合(Set),然後從集合中減掉每一個產生的序列中的元素。
不過正如你所見,為了真正的刪除掉這些倍數,我們使用了一個外部的可變集合,這會帶來副作用。
我們總是應該嘗試消除副作用,所以我們先計算所有的子序列,然後調用 flatMap
方法將其中所有的元素展開,存放到單個數組中,最後再從原始的集合中刪除這些整數。
var sameprimes = Set(2...n) sameprimes.subtractInPlace((2...Int(sqrt(Double(n)))) .flatMap{ (2*$0).stride(through:n, by:$0)})sameprimes.sort()
使用析構交換元組中的值
既然是福利,自然並非每個人都知道這一點。和其他具有元群組類型的語言一樣,Swift 的元組可以被用來交換兩個變數的值,代碼很簡潔:
var a=1,b=2 (a,b) = (b,a)a //2b //1
以上就是全部內容,正如我們預料的那樣,Swift 和其他語言一樣富有表現力。