標籤:遞迴 數組 遍曆 swift
title: “Why coding like This —— 遞迴以及枚舉中的遞迴”
date: 2015-08-28 21:34:16
categories: “why coding like this”
tags: [swift進階]
Topic 1:
輸入一個數組xs:[Int],對全體元素求和。
Discuss
- 思路一: Hey,夥計,遍曆數組,逐個相加,so easy!
code:
func sum1(xs:[Int])->Int{ var sum:Int = 0 for x in xs{ sum += x }}
- 思路二: 假設已經有一個對數組求和函數sum2,那麼我是否可以這麼分解:
sum([2,3,5]) = 2 + sum([3,5]) = 2 + 3 + sum([5]) = 2 + 3 + 5 + sum([])
我們採用將數組分解成首元素和剩餘數組元素組成的數組的方式遞迴,直到剩下一個空數組求和(此時返回0),完成對數組[2,3,5]的求和。再寫具體求和函數之前,我們要小小拓展下Array,添加一個decompose計算屬性,它的作用是返回對當前數組的分解結果,一個類型為(head:T,tail:[T])?的元組,由於數組可能存在空數組的情況,此時分解必定返回nil,因此不難理解這個元組是可選類型。
code
extension Array{ var decompose:(head:T,tail:[T])?{ //通過數組元素個數來判斷是否為空白數組 空數組則返回nil //否則返回首元素 和剩餘元素組成的數組 //特殊的是單個元素數組[x] 返回 x 和空數組[] return (count > 0) ? (self[0],Array(self[1..<count])) : nil }}
接下來使用遞迴實現sum2函數,通過上面的理解灰常好寫:
func sum2(xs:[Int])->Int{ //如果是空數組 元組為nil 返回0值即可 if let (head,tail) = xs.decompose{ return (head + sum2(tail)) //遞迴 }else{ return 0 }}
以上是對遞迴的一次淺嘗接下來對swift2.0文法中首現的枚舉遞迴用法進行理解
Topic 2:
使用枚舉中的遞迴對錶達式(5 + 4) * 2 求值。
Discuss
首先分析運算式,主要分為數字(Number)和運算子 +、-、*、/,往往運算子的兩側分別是number。因此假如使用枚舉,我們會如此定義
enum ArithmeticExpression{ case Number(Int) indirect case Addition(ArithmeticExpression, ArithmeticExpression) indirect case Multiplication(ArithmeticExpression, ArithmeticExpression) //這裡你還可以添加減法和除法}
注意到indirect關鍵字了嗎,這便是指示枚舉遞迴。定義好資料結構,我們還需要一個函數用於運算式解析,函數傳入ArithmeticExpression類型值,可能是number綁定數字,例如.Number(5)表示為單個數字5;也可能是一個運算子綁定左右的運算資料,例如.Addition(5,4) = 5 + 4.具體如下
func evaluate(expression: ArithmeticExpression) -> Int { switch expression { case .Number(let value): return value case .Addition(let left, let right): return evaluate(left) + evaluate(right) case .Multiplication(let left, let right): return evaluate(left) * evaluate(right) }}// 求運算式 (5 + 4) * 2let five = ArithmeticExpression.Number(5)let four = ArithmeticExpression.Number(4)let sum = ArithmeticExpression.Addition(five, four)let product = ArithmeticExpression.Multiplication(sum, ArithmeticExpression.Number(2))print(evaluate(product))// prints "18"
不得不說官方給出的例子可能讓很多朋友失望,這並不是一個完整的傳入運算式給你值的例子,但是讓你理解了枚舉中的遞迴。
對了以上代碼只能運行在Xcode7 新版本beta下。 不過!是的,我有方法讓代碼同樣適用於swift1.2文法,只是需要小小封裝下。
class Box<T>{ let unbox : T init(_ value:T){self.unbox = T}}//由於swift1.2下是不支援泛型關聯值的enum enumTypeError<T>{ case type1(NSError) case type2(T)}//但是我們可以如此改動enum enumTypeSuccess<T>{ case type1(NSError) case type2(Box<T>)}//同理你可以封裝下上面的枚舉 作為challenge!
本書參考了官方文檔以及Functional Programming in swift 這本書,僅作為學習的筆記分享給大家。說實話這篇文章略水,其實早前是想先搞scrollView的揭秘文章,想庖丁解牛從基礎講到所有,但是無奈寫完後略水,很多自己懂但沒有表述出來,因此打算回爐重造!相信不久就能和大家見面。另外swift2.0最新文法 我已經更新到github上 是官方8.24最新版本。github地址,希望star下 你也可以關注我的微博地址.
著作權聲明:本文為博主原創文章,未經博主允許不得轉載。
Why coding like This ------ 遞迴以及枚舉中的遞迴