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

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

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

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

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

邏輯難題

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

美元硬幣

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

初探問題

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

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

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

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

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

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

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

先造硬幣

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

  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

指令式編程的一個重要觀點是:變量改變狀態。指令式的程序像是一種微型控制器,它告訴計算機如何完成任務。接下來的 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 美分,也就是最小的面額,那沒有繼續拆分的可能性,直接返回1作為結束。

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

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

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

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

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

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

 

  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 。將數組進行切分在下標越界的情況下也不會引發異常。如果數組中只剩下一個元素,這時 smallerCoins 就為空。

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

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

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

思考

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

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

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

2013-09-09 09:41:34

2015-06-25 09:42:47

swift蘋果開源

2011-08-24 09:13:40

編程

2023-12-14 15:31:43

函數式編程python編程

2022-09-22 08:19:26

WebFlux函數式編程

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編程函數

2017-06-08 14:25:46

Kotlin函數

2010-11-25 09:06:37

Web開發函數式編程

2020-09-22 11:00:11

Java技術開發

2016-08-11 10:11:07

JavaScript函數編程

2016-08-11 10:34:37

Javascript函數編程

2020-09-23 07:50:45

Java函數式編程

2010-03-11 10:34:22

Scala

2012-09-21 09:21:44

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

2019-09-09 11:40:18

編程函數開發

2020-10-22 06:29:39

編程前端開發

2022-07-07 09:03:36

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

51CTO技術棧公眾號

主站蜘蛛池模板: 婷婷福利 | 亚洲精品久久久一区二区三区 | 亚洲免费视频一区 | 久久亚洲一区二区 | 国产一区二区三区四区五区加勒比 | 99精品观看| 久久国产精品视频 | 综合色久 | 玖玖玖在线| 久久精品视频在线免费观看 | 资源首页二三区 | 亚洲一视频 | 亚洲字幕在线观看 | 成人精品国产 | 欧美综合国产精品久久丁香 | 国产视频久久久 | 日韩国产高清在线观看 | 成人激情免费视频 | 久久久久国产一区二区三区四区 | 91精品久久久 | 国产丝袜av| 欧美精品一 | 国产日韩久久 | www.色综合| 久草.com | 中文字幕一区二区三区日韩精品 | 国产精品久久久久久久久久免费看 | 免费一级毛片 | 国产一区二区在线播放 | 国产电影一区二区 | 6996成人影院网在线播放 | 亚洲精品在线看 | 日韩电影中文字幕 | 精品日韩一区二区三区 | 亚欧洲精品在线视频免费观看 | av资源中文在线天堂 | 久久久久免费 | 亚洲精品福利在线 | 亚洲97 | 91天堂 | 国产精品久久久久久中文字 |