成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

用函數式編程解決邏輯難題 - Swift 版本

移動開發(fā) iOS
這篇翻譯的文章,用兩種方法解決了同一個邏輯難題。第一種方法的編程風格接近大多數 iOS 開發(fā)者,實現了指令式編程的解決方案。第二種方法利用了 Swift 的一些語言特性,實現了函數式編程的解決方案。

這篇翻譯的文章,用兩種方法解決了同一個邏輯難題。第一種方法的編程風格接近大多數 iOS 開發(fā)者,實現了指令式編程的解決方案。第二種方法利用了 Swift 的一些語言特性,實現了函數式編程的解決方案。

源代碼可以在這里下載:https://github.com/ijoshsmith/break-a-dollar

邏輯難題

前陣子朋友和我說起,把1美元分解成更小的面額,有293種方法。換句話說,如果一個哥們兒告訴你他有1美元,那么他的手里有293種可能的組合,有可能是兩個50美分,也可能是4個25美分。第二天,我就開始嘗試用代碼去解決這個問題。這篇博客回顧了當時想到的兩種解決方案。

美元硬幣

對于不熟悉美元硬幣的同學,可以先了解一下美元的硬幣。如下圖所示,1美元(dollar) = 100美分(cent):

初探問題

思考后我發(fā)現用一種比較簡單骯臟的手段解決這個問題并不難,但是這還遠遠不夠。我想找到一種優(yōu)雅的解決方案,所以我嘗試從各個角度思考這個問題,最終得到了想要的答案。

解決這個問題的關鍵在于遞歸的分解問題。“如何用各種硬幣組合拼成1美元”,更寬泛點講,其實就是“如何用各種硬幣組合拼成指定金額”。

舉個人民幣的例子。你欠人家100塊,人家說你100塊都不給我。你說好,我給!于是掏出兩張50,這便是一個50+50的解決方案。

這時你發(fā)現有一張是嶄新的50,你不想給他這張50,于是你的問題變成了:如何用手里的碎錢組合出50面額的錢。

后來你把50換成了5張10塊,這便是一個50+10*5的解決方案,然后感覺有一張10塊是嶄新的,要不我換成硬幣給他。

于是問題又變成了:如何組合出10面額的錢。就是這樣慢慢拆分下去。

點擊 這里 查看完整的算法回顧。

先造硬幣

我多次提到“硬幣”這個詞,實際上一枚硬幣也就是一個整數值,代替了它價值多少美分。我寫一個枚舉類存儲所有的硬幣面額,然后再用一個靜態(tài)方法降序返回所有的值:

  1. enum Coin: Int { 
  2.     case SilverDollar = 100 
  3.     case HalfDollar   = 50 
  4.     case Quarter      = 25 
  5.     case Dime         = 10 
  6.     case Nickel       = 5 
  7.     case Penny        = 1 
  8.     static func coinsInDescendingOrder() -> [Coin] { 
  9.         return [ 
  10.             Coin.SilverDollar, 
  11.             Coin.HalfDollar, 
  12.             Coin.Quarter, 
  13.             Coin.Dime, 
  14.             Coin.Nickel, 
  15.             Coin.Penny, 
  16.         ] 
  17.     } 
  18. }

解決方案1:指令式編程 - Imperative

指令式編程的一個重要觀點是:變量改變狀態(tài)。指令式的程序像是一種微型控制器,它告訴計算機如何完成任務。接下來的 Swift 代碼大家看起來應該都不陌生,因為 objc 就是一種指令式的編程語言:

  1. func countWaysToBreakAmout(amount: Int, usingCoins coins:[Coin]) -> Int{ 
  2.     let coin = coins[0
  3.     if (coin == .Penny) { 
  4.         return 1 
  5.     } 
  6.     var smallerCoins = [Coin]() 
  7.     for index in 1..!=coins.count { 
  8.         smallerCoins.append(coins[index]) 
  9.     } 
  10.     var sum = 0 
  11.     for coinCount in 0...(amount/coin.rawValue) { 
  12.         let remainingAmount = amount - (coin.rawValue * coinCount) 
  13.         sum += countWaysToBreakAmout(remainingAmount, usingCoins: smallerCoins) 
  14.     } 
  15.     return sum 

仔細看下上面的代碼,計算過程一共分三步:

首先取出可用數組中的第一個硬幣,如果這枚硬幣已經是 1 美分,也就是最小的面額,那沒有繼續(xù)拆分的可能性,直接返回1作為結束。

然后創(chuàng)建了一個數組 (smallerCoins) ,存儲比當前硬幣更小的硬幣,用來作為下次調用的參數。

最后計算除去第一次取出的硬幣之后,還有多少種解決方案。

這樣的代碼對于指令式編程來說再平常不過,接下來我們就來看下如何用函數式編程解決這個問題。

解決方案2:函數式編程 - Functional

函數式編程的依賴對象,是函數,而不是狀態(tài)變化。沒有太多的共享數據,就意味著發(fā)生錯誤的可能性更小,需要同步數據的次數也越少。 Swift 中函數已經是一等公民,這讓高階函數變成可能,也就是說,一個函數可以是通過其它函數組裝構成的。隨著 objc 中 block 的引入, iOS 開發(fā)者對這個應該并不陌生。

下面是我的函數式解決方案:

 

  1. func countWaysToBreakAmount(amount: Int, usingCoins coins:Slice) -> Int{ 
  2.     let (coin, smallerCoins) = (coins[0], coins[1..<coins.count])     if (coin ="= .Penny) {"         return 1=""     }=""     let coincounts =" [Int](0...amount/coin.rawValue)"     return coincounts.reduce(0) { (sum, coincount) in=""         let remainingamount =" amount - (coin.rawValue * coinCount)"         return sum + self.countwaystobreakamount(remainingamount, usingcoins: smallercoins)="" }
  3.             </coins.count])> 

 

<="" pre="">

第二個參數是 Slice而不是數組,因為沒必要把硬幣拷貝到新的數組里。我們只需要用數組的一個切片就可以,也就是第一行代碼里的 smallerCoins ,在函數式編程里稱之為 tail 。我們把數據中的第一個元素稱之為 head ,剩下來的部分稱之為 tail 。將數組進行切分在下標越界的情況下也不會引發(fā)異常。如果數組中只剩下一個元素,這時 smallerCoins 就為空。

我用元組的語法同時獲取了 coin 和 smallerCoins 這兩個數據,因為取頭取尾可以說是同一個操作。與其寫一堆代碼去解釋如何先取出第一個元素,然后再獲取剩下的元素,不如直接用“取出頭部和尾部”這樣語義化的方式一步到位。

接下來,也并沒有采用循環(huán)然后改變局部變量的方法來計算剩余的組合數,而是用 reduce 這個高階函數。如果你對 reduce 這個函數不太熟悉,可以看下這篇文章有個大概的了解。

首先 coin 指當前處理的硬幣, coinCounts 是一個數組,里面存儲了所有當前面額的硬幣的可能出現的數目。比如 amount 是10, coin 是3,那么 coinCounts 的值就是,面額為3的硬幣可能有多少。顯然應該最多出現3個,所以 coinCounts 是 [1,2,3] 這樣的一列數。然后在分別對每種情況進行分解計算。

思考

Swift 對于函數式編程的支持讓我感覺的興奮,Excited!換種方式思考或許是個不小的挑戰(zhàn),但是這都是值得的。幾年前我自學了一些 Haskell ,我很欣喜的發(fā)現一些函數式思考習慣,讓我在 iOS 開發(fā)中也能受益匪淺。

示例項目的源代碼可以在這里下載。

責任編輯:chenqingxiang 來源: cocoachina
相關推薦

2013-09-09 09:41:34

2015-06-25 09:42:47

swift蘋果開源

2016-10-31 20:46:22

函數式編程Javascript

2011-03-08 15:47:32

函數式編程

2020-09-24 10:57:12

編程函數式前端

2025-03-11 10:00:20

Golang編程函數

2011-08-24 09:13:40

編程

2023-12-14 15:31:43

函數式編程python編程

2022-09-22 08:19:26

WebFlux函數式編程

2017-06-08 14:25:46

Kotlin函數

2010-11-25 09:06:37

Web開發(fā)函數式編程

2020-09-23 07:50:45

Java函數式編程

2010-03-11 10:34:22

Scala

2012-09-21 09:21:44

函數式編程函數式語言編程

2020-09-22 11:00:11

Java技術開發(fā)

2016-08-11 10:11:07

JavaScript函數編程

2016-08-11 10:34:37

Javascript函數編程

2019-09-09 11:40:18

編程函數開發(fā)

2020-10-22 06:29:39

編程前端開發(fā)

2022-07-07 09:03:36

Python返回函數匿名函數
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 玖玖爱365 | 男人天堂99| 欧美精品久久久久久久久老牛影院 | 日韩成人免费视频 | 亚洲免费在线视频 | 亚洲欧美视频 | 欧美精品乱码99久久影院 | 欧美一级久久精品 | 久久33| 欧洲妇女成人淫片aaa视频 | 97人人澡人人爽91综合色 | 九九热免费看 | 国产激情视频在线 | 美日韩精品 | 成人网在线观看 | 少妇淫片aaaaa毛片叫床爽 | 精品一区二区在线观看 | 激情免费视频 | 蜜月aⅴ国产精品 | 嫩草黄色影院 | 色视频在线播放 | 亚洲视频中文 | 亚洲综合三区 | 国产精品夜间视频香蕉 | 精品一区二区在线观看 | 日韩视频一区在线观看 | 国产精品国产馆在线真实露脸 | 91视频正在播放 | 亚洲午夜网 | 国产a级黄色录像 | 日韩有码在线观看 | 中文字幕在线免费观看 | 91在线精品一区二区 | 久久久久国产精品一区 | 97精品一区二区 | 我我色综合 | www.亚洲| 91伊人网| 成人高潮片免费视频欧美 | 久久久精品亚洲 | 亚洲精品短视频 |