Why Coding like This?—— Reduce 函數(shù)揭秘

3.Reduce 函數(shù)揭秘

Topic 3:

請用Reduce函數(shù)對Int類型數(shù)組內(nèi)所有元素求和虐译,例如數(shù)組[1,2,3,4]的4個元素和為10.

Example:

//例一:
let intArray = [1,2,3,4]

var sum = intArray.reduce(0){
  result, x in
  result + x
}

why coding like this?

1.開篇

命題一:假設(shè)讓你寫一個函數(shù)來實現(xiàn)對Int類型數(shù)組內(nèi)所有元素求和帕识,例如數(shù)組[1,2,3,4]的求和結(jié)果為10。
思路:與類map,filter函數(shù)思路不同,前者是對數(shù)組內(nèi)每一個元素單獨做處理车要,而reduce恰恰相反惶岭,是將所有數(shù)組元素整合到一起。因此關(guān)于求和函數(shù)思路很明確馁痴,遍歷整個數(shù)組元素,逐一求和后作為結(jié)果值返回肺孤,大致為 0 + 1 + 2 + 3 +4罗晕。其中0是初始值。
代碼:

//例二:
func sum(xs:[Int])->Int{
  var result:Int = 0
  for x in xs{
    result += x
  }
  return result
}
//不妨測試下
sum(intArray)//print 10

可以看到對于sum函數(shù)傳入Int類型數(shù)組赠堵,首先我們聲明一個Int類型變量用于保存最后的求和結(jié)果值小渊,初始值為0;接著使用for-in語句遍歷傳入的數(shù)組茫叭,使用result += x逐一求和累加酬屉;最后返回結(jié)果值result。

2.過渡

命題二:基礎(chǔ)入門之后揍愁,按照慣例對條件進(jìn)行改變呐萨,假如把所有元素求和更改為對所有元素求乘,如[1,2,3,4] 返回1 * 2 * 3 * 4 = 24莽囤。
思路:顯然對于前面的代碼稍許改動即可谬擦,主要是替換result += x(累加運算) 更為result = result * x(階乘運算)。當(dāng)然有一點切記不要遺忘朽缎,就是初始result = 1惨远。
代碼:

//例三:
func multiplicator(xs:[Int])->Int{
    var result:Int = 1
    for x in xs{
        result = x * result
    }
    return result
}
multiplicator(intArray)//輸出24

命題三: 說完Int類型數(shù)組蔚舀,再來說說String類型,將一個文字片段數(shù)組組成一個完整的句子,例如["hello"," ","world","!","say"," ","by"," ","optionalswift"],最后整合成"hello world!say by optionalswift"锨络。
思路: 思路大概是遍歷數(shù)組赌躺,然后將所有字符串元素拼接在一起,關(guān)鍵這個拼接用什么羡儿?例如有str1str2礼患,swift中其實只需要簡單的newStr = str1 + str2 即可。
代碼:

//例四:
func jointStringArray(xs:[String])->String{
  var result :String = ""
  
  for x in xs{
    result += x
  }
  return result
}
let helloworld = ["hello"," ","world","!","say"," ","by"," ","optionalswift"]
jointStringArray(helloworld)//輸出"hello world!say by optionalswift"  

你已經(jīng)急著上手想寫泛型函數(shù)了嗎掠归?等等缅叠,我們貌似還忽略了一些復(fù)雜的鏈接情況。比如["hello","world","say","By","optional"]虏冻,我們需要在每一個單詞之間插入"-"連字符肤粱,別問我為什么?因為是我出題厨相!

//例五:hyphen 意思為連字符`-`
func jointStringArrayByHyphen(xs:[String])->String{
  var result : String = "整合后的字符串為:"
  for x in xs{
    result = result + "-" + x  //注意右側(cè)是一個類似combine(result,x)函數(shù)進(jìn)行處理 得到整合后的結(jié)果給result
  }
  return result
}
let newArray = ["hello","world","say","By","optional"]
jointStringArrayByHyphen(newArray)//輸出"整合后的字符串為:-hello-world-say-By-optional"

3.高潮

在開始寫我們的泛型reduce函數(shù)之前领曼,分析函數(shù)的輸入輸出以及如何實現(xiàn):首先該函數(shù)將傳入一個泛型類數(shù)組,暫且定為[T]蛮穿;此外函數(shù)可自己設(shè)定初始值給result庶骄,暫且定為U;最后是重中之重:傳入一個閉包作為連接result和數(shù)組元素的處理函數(shù)践磅,combine(result,x)单刁,不難分析result的類型為T,x是數(shù)組xs中的元素,類型為U府适,返回嘛自然是和result一致的類型嘍羔飞。因此combine閉包類型為(U,T)->U。因此代碼這么寫:

//例六:
func myReduce<T,U>(arr:[T],initialValue:U,combine:(U,T)->U)->U{
  var result = initialValue //賦值初始值 類型為U 并且是作為結(jié)果值返回的
  for elem in arr{
    result = combine(result,elem)   //注意右側(cè)是傳入的閉包 該閉包類型為(U,T)->U,即把上一次的結(jié)果值依次和數(shù)組元素做拼接處理檐春,該處理可在閉包中實現(xiàn)逻淌,取決于你
  }
  return result
}
myReduce(newArray, "整合后的字符串為:"){
  result , elem in //注意result ,x 于combine(result,elem)相對應(yīng)
  return result + "-" + x //注意這里return 其實是可以省略的!
}

不得不說喇聊,這個函數(shù)還是有點料的恍风,需要細(xì)細(xì)品味一番蹦狂。你以為這就結(jié)束了嗎誓篱,還有落幕呢?

4.落幕

對sum函數(shù)進(jìn)行改寫凯楔,使用前面自定義的myReduce函數(shù)封裝

func sumUsingReduce(xs:[Int])->Int{
    return myReduce(xs,0){result, x in result + x}
}

注意到省略了return 因為swift會幫你推算要返回什么窜骄。簡化的感覺不夠徹底。

func sumUsingReduce(xs:[Int])->Int{
    return myReduce(xs,0,+)
}

閉包僅僅傳入了一個+號摆屯,swift推算過程是首先combine閉包有兩個傳入?yún)?shù)result和elem,除此之外別無其他邻遏,因此+只能對這兩個參數(shù)求和糠亩,得到一個結(jié)果值x,由于combine函數(shù)還需要返回一個結(jié)果值准验,但是思來想去貌似除了x沒有其他可用赎线,因此把x作為閉包結(jié)果值返回和result相加。

類似的你可是使用return myReduce(xs,1,*)糊饱。

你以為這就結(jié)束了嗎垂寥? 現(xiàn)在用reduce來改寫map函數(shù) 以及filter函數(shù)

func mapUsingReduce<T,U>(xs:[T],f:T->U)->[U]{
    return xs.reduce([]){result,x in result + [f(x)]}//使用了系統(tǒng)API 嘗試用自定義的
}

首先注意到函數(shù)傳入的兩個參數(shù)以及返回結(jié)果值和早前map函數(shù)是一模一樣的,關(guān)鍵是在主體的實現(xiàn)上!

再來看filter的實現(xiàn):

filterUsingReduce<T>(xs:[T],check:T->Bool)->[T]{
    return xs.reduce([]){
        return check(x) ? result + [x] : result //使用了系統(tǒng)API 嘗試用自定義的
    }
}

map另锋,filter滞项,reduce 小節(jié)至此結(jié)束! 希望對大家有收獲夭坪!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末文判,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子室梅,更是在濱河造成了極大的恐慌戏仓,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,509評論 6 504
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件亡鼠,死亡現(xiàn)場離奇詭異柜去,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)拆宛,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,806評論 3 394
  • 文/潘曉璐 我一進(jìn)店門嗓奢,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人浑厚,你說我怎么就攤上這事股耽。” “怎么了钳幅?”我有些...
    開封第一講書人閱讀 163,875評論 0 354
  • 文/不壞的土叔 我叫張陵物蝙,是天一觀的道長。 經(jīng)常有香客問我敢艰,道長诬乞,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,441評論 1 293
  • 正文 為了忘掉前任钠导,我火速辦了婚禮震嫉,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘牡属。我一直安慰自己票堵,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,488評論 6 392
  • 文/花漫 我一把揭開白布逮栅。 她就那樣靜靜地躺著悴势,像睡著了一般窗宇。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上特纤,一...
    開封第一講書人閱讀 51,365評論 1 302
  • 那天军俊,我揣著相機(jī)與錄音,去河邊找鬼捧存。 笑死模暗,一個胖子當(dāng)著我的面吹牛水援,可吹牛的內(nèi)容都是我干的趴生。 我是一名探鬼主播杠河,決...
    沈念sama閱讀 40,190評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼傻咖!你這毒婦竟也來了朋魔?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,062評論 0 276
  • 序言:老撾萬榮一對情侶失蹤卿操,失蹤者是張志新(化名)和其女友劉穎警检,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體害淤,經(jīng)...
    沈念sama閱讀 45,500評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡扇雕,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,706評論 3 335
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了窥摄。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片镶奉。...
    茶點故事閱讀 39,834評論 1 347
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖崭放,靈堂內(nèi)的尸體忽然破棺而出哨苛,到底是詐尸還是另有隱情,我是刑警寧澤币砂,帶...
    沈念sama閱讀 35,559評論 5 345
  • 正文 年R本政府宣布建峭,位于F島的核電站,受9級特大地震影響决摧,放射性物質(zhì)發(fā)生泄漏亿蒸。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,167評論 3 328
  • 文/蒙蒙 一掌桩、第九天 我趴在偏房一處隱蔽的房頂上張望边锁。 院中可真熱鬧,春花似錦拘鞋、人聲如沸砚蓬。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,779評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽灰蛙。三九已至,卻和暖如春隔躲,著一層夾襖步出監(jiān)牢的瞬間摩梧,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,912評論 1 269
  • 我被黑心中介騙來泰國打工宣旱, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留仅父,地道東北人。 一個月前我還...
    沈念sama閱讀 47,958評論 2 370
  • 正文 我出身青樓浑吟,卻偏偏與公主長得像笙纤,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子组力,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,779評論 2 354

推薦閱讀更多精彩內(nèi)容