那講完了這個 tuple 的一些基本的東西,我們來看一個簡單的這個例子,那這個簡單的 例子就是從上一次講這個台灣身份證字號的計算這個 checksum 的 部分,那我們事實上上禮拜 我們有介紹過說怎麼樣去驗證一個台灣的身份證字號,對不對? 那我們現在就是說針對這個最後計算 checksum 的這個 部分,我們來討論一下這個 tuple 可以扮演什麼樣的角色。 那所以我們大概回顧一下,這個身份證字號的 checksum 是怎麼 做呢,它是把身份證字號的第一個字母,把它轉成一個兩位的一個 數字,然後呢把這兩位數字跟後面的 9,原來的後面的 9 位的數字串接之後呢變成一個 11 位的數字, 這 11 位的數字呢就是每一個位置會有一個不同的權重,然後呢每一個數字乘以不同的權重加起來 變成一個 checksum,然後再除以 10 求餘數嘛。 那我們現在就是說簡化,我們就看這個 就是算這個 checksum 還沒有除以 10 之前的那個部分。 那所以我們來回顧一下,如果說我們現在 要有程式去做這個部分,要怎麼做呢?所以一樣,我們就是定義一個叫做 cksum_twid 的這個函數,然後它的這個參數是一個 idstr 這樣子的東西,那我們一樣,就是說這個是從上一次的這個 程式來的,那我們一樣就是把這個 idstr 的 第 1 個位置,第 0 個位置的這個 英文數字拿出來,把它轉成內部的編碼, 然後呢我們定義的這個英文數字,這個到這個兩位數字的中間的這個 mapping,用這個 list,對不對?然後呢我們的這個 這個 mapping 的方式就是把它轉成內部編碼之後扣掉 65,因為這邊這個 65 的 內部編碼剛好是 A 嘛,所以 A 就 map 到 0,對不對? 以此類推,對不對?然後呢有了這個兩位數字之後 我們把它轉成這個字串跟後面的部分串接, 然後還有一個權重,對不對?權重是這樣,1,9,8,7,6,5,4,3,2,1,1,- 對不對? 然後呢我們就開始跑一個迴圈,從 0 跑到 10,對不對?然後每一次就是把 那個位置的權重乘以那個位置的值, 然後呢算出來之後呢,把它累加到 checksum 裡面,checksum 一開始是 0,最後印出 checksum,對不對? 所以這個是只有 checksum 的部分,那所以如果你的 id 傳進去是 A123456789 的話,那 checksum 會印出說這個 checksum 是 130,checksum 是 130,當然你如果不相信你可以回去驗算一下,你可以拿紙筆來算一下。 那這個東西呢我們可以怎麼樣 利用這個一些 tuple 的這個相關的這個東西來修改呢? 那我們就來介紹一下一個特殊的函數叫做 zip, 那 zip 這個東西其實還蠻有趣的,那 zip,大家不知道這個知不知道 這個日常生活 zip 常常用的就是說你 拉拉鏈的時候叫做 zipping,對不對?拉鏈怎麼運作呢? 拉鏈就是說,拉鏈就是它有兩邊嘛,那你拉鏈拉起來的時候是怎樣?它就是把 兩邊合起來,大家想一下這個拉拉鏈的動作, 那對呀,最近還有一個 很有名的電影叫做 la la land,對不對?我覺得還蠻好看的。 那所以 zipping 基本上就是把兩個東西合起來,對不對?那這個 事情在這個一個我們在這邊的這個操作是什麼意思呢? 在這邊的操作就是還蠻有趣的,你看這個 newid 裡面總共有 11 位 數字,對不對?那這個權重呢裡面呢剛好有 11 個權重, 對不對?那你如果把這兩個東西 zip 起來的時候,做的事情是什麼呢?做的事情事實上是 把它一個一個配對,一個一個配對之後呢變成一個 變成 11 組的 tuple,每一組的 tuple 呢 都有一個身份證字號裡面的某一個這個 位數,某一個這個 digit 再搭配它的權重。 那我不知道大家能不能這個 理解這個東西啦,那就是說呢,基本上它的想法就是說呢你看我們現在做的事情是去 zip 兩個東西,對不對?我們是要 zip,我們這邊做的事情是 zip newid 跟 weght,那 newid 它本身是一個 string,對不對?所以它呢就是會 事實上可以看成是 11 個 這個 character,這邊有 11 個 character,然後每一個 character 呢在 zip 的時候呢就會搭配這個 weight 的相對位置的這個數值,所以 這個字串 1 會對到 1,字串 0 會對到 9, 字串 1 會對到 8,字串 2 會對到 7,依此類推,所以最後這個 9 就會對到這個 1,所以呢我們如果說用一個迴圈去把這個 zip 這兩個變數的這個結構給它印出來的話呢, 會是怎樣呢?它就會像這個樣子, 就是這個字串 1 對 1,字串 0 對 9, 字串 1 對 8,字串 2 對 7,字串 3 對 6,一路下來 就是如同這邊講的,是這樣子的對應,對不對?是這樣子的對應。 那所以這個就是 zipping,所以你現在大概可以理解為什麼它叫 zip,就是說它就像拉鏈一樣把兩邊合起來。 那這個東西對我們有用嗎?其實還蠻有用的,因為我們在做 checksum 的時候是在做什麼事情呢?我們是把每一個位置 apply 一個不同的權重, 對不對?那這個動作呢似乎就跟這個拉拉鏈 的這個事情還蠻像的,對不對?還蠻像的, 那所以呢我們就可以用這個 zip 這個 函數來修改我們的這個結果,那另外就是說呢 你看這個每一個 output 事實上它是一個 tuple,事實上是一個 tuple,所以你可以知道就是說 tuple 事實上是在這個各式各樣的運算裡面扮演 一些角色啦,就是說它有時候還蠻隱形的,但是就是說偶爾你就會看到,偶爾你就會看到。 那所以呢,如果說我們照前面這樣子下去修改的話,我們就做出一個 第二版的一個這個東西,前面都一樣,那唯一的差別就是說呢 是在這個地方,就是說呢我們現在把這個 newid 做出來之後呢,我們就是用前面做的那個方法,是 zip newid 跟 weight,然後呢 loop through 所有的 zipping 之後的 pair, 那每一個 pair 就是一個這個 newid 裡面的這個 string 跟它的權重的數值嘛, 所以我們一樣,就是說因為它 zip 出來是一個 tuple,tuple 的位置 0 就是原來 newid 的 string,那位置 1 就是權重,所以我們 一樣是把這個 tuple 裡面的位置 0 把它轉成 int 之後呢 跟這個權重相乘,然後呢累加到 checksum 裡面, 那所以這個做法呢就是,就可以取代掉之前,是 loop through 這個 每一個 element 然後去抓相對的這個 element 這個事情。 那所以呢這個結果呢,就是說在這邊執行的結果就會跟原來一樣, 對不對?你如果傳入一樣的東西就會得到一樣的結果,所以它基本上是類似的運算,但是是用- 不同的方法,那這邊是用 zip。 有人說這樣子有比較好嗎?有沒有比較好,見仁見智,那但是 就是 zip 這個做法在有些地方呢是還蠻方便的,那你 要不要使用是你的決定,那但是就是說我們現在就是告訴你說你可以有這樣子的一個選擇,這- 樣子的一個選擇。 那這個東西事實上呢可以再進一步地往下走,怎麼說呢, 那 python 其實它還有提供一些別的東西, 那也是就是說我們常常認為這些東西是比較 python style 的 東西,python style 就是說呢它在別的語言呢可能找不到比較類似的東西或者 比較少看到類似的東西,但是在 python 的這個語言裡面是比較常見的, 那我們後面會介紹兩個東西,是類似這樣子的東西。 那 python style 的東西就是說呢, 有些人喜歡有些人不喜歡,那就像是榴蓮有些人喜歡有些人不喜歡,喜歡的人覺得說 這是一個很棒的東西,不喜歡的人覺得說為什麼要這樣子,就是沒有必要。 那所以就是說我們在這邊就是介紹這些比較是 python style 的東西,那你可以自己決定說你希望要不要用。 那一個東西就是 lambda,lambda operator, lambda operator 是一個什麼東西呢?lambda operator 是一個定義簡單 函數的一個方式,那你會說什麼叫定義簡單函數呢?那我們在這邊看一個簡單的 例子,就是說假設每個函數它做的事情很簡單,它就是把傳入的這個變數把它 平方,所以這個 ** 就是是開幾次方的意思,所以這邊是平方。 所以定義好這個 f1 之後,你如果把 f1 傳入 8 的話,它就會傳出 64, 對不對?這個是還蠻合理的,是吧? 那我們同樣的事情,我們可以用 lambda 這個 operator 來做,你可以說 lambda x: x**2,所以在這邊這個 lambda 後面接的這個 x 就是相當於你在定義函數時候的傳入值,傳入值, 那這個冒號後面就是接傳出值,傳出值。 然後呢,所以這個 lambda 這個東西呢本身就是定義一個函數,那有趣的地方就是說 你在這邊定義的這個函數是沒有名字的。 那你當然可以把它取一個名字,取名的方式就是說 你定義一個新的變數比如說叫 f2,那 f2 呢就是去 就是說,你就可以說 f2 就是你剛剛定義的這個函數。 所以呢,你這時候呢,所以這個 f2 是一個變數,而且這個變數 本身呢,是對應到一個函數。 所以你如果說 你如果拿著個 f2 呢,然後傳進去 8 的話,就告訴你是 64。 好,所以基本上呢,你可以把它看成一樣是一個定義函數的 方式,那只是說它的語法不大一樣,而且通常我們在使用這個 lambda 的時候,我們通常就是只有用,只有大概是一行。 那這個一行的意思是就說,我們通常不會定義太複雜的東西。 就是說如果它是一個簡單的函數的話,你可以用 lambda 來定義,好。 那這樣子做呢,有什麼好處呢?lambda 這個東西呢,通常會 搭配其他的東西使用,所以我們來介紹一個它常常會搭配的東西叫做 map。 那 map 也是一個操作,那這個操作是做什麼事情呢?map 就是說呢,如果說你有一個 list 好,或者有一個 tuple,那這個 list 或 tuple 裡面有很多很多元素嘛,那你希望把這個 裡面的所有的每一個元素呢,都 apply 同樣的一個操作、 同樣的一個函數的話呢 這時候,你就可以用這個 map 這個 operator,那所以我們 就是 follow 前面的這個例子,我們就說假設我們現在有一個 list,這個 list 裡面有一堆數字 我們需要把裡面的每一個數字都平方以後,產生一個新的 list,我們想要做這個事情,好。 那這個時候呢,我們就可以用這個 map 的這個 operator 來做啊,比如說我們定義一個 list1 它裡面有 3 哪 5 啊、 1.2 啊、 4 啊、 9 啊這些數字,然後呢如果說呢,我們 map f1 list1 的話呢,意思就是說我們把 f1 我們是前面定義的一個那個函數,對不對?它就是去把 這個傳入值平方,對不對?然後 apply 到 list1 的每一個元素 然後把輸出,把這個結果擺到 out1 裡面。 然後呢,這時候呢,我們如果去列印 out1 的內容的時候呢 它就會是類似像這樣子的東西。 那 這個 out1 這個東西,它是一個 iteratable 的一個東西,意思說你可以用 for 迴圈去看,或者說你可以直接把它轉成 list 或是轉成 tuple,那在這邊我們就把它轉成 list。 就變成這個樣子,所以你可以看到每一個就是是原來的平方,好,對不對。 原來的平方,有沒有。 那所以這個是一個做法哦,那另外一個做法 就是說因為你如果要用一個函數,比如說 f1 你必須要在前面先定義,對不對。 那有些時候呢 這個東西呢,就是用過就要丟掉,對不對。 那有時候講說啊定義這麼多東西 要幹什麼。 那所以另外一個做法就是用這個 lambda operator,好。 所以呢,同樣的事情,你一樣可以是 map,但是你在傳函數的時候呢,你就直接用 lambda 的這個 operator 去定義這個函數,所以 lambda x: x**2 對不對? 所以這邊定義就是你傳進去的東西就是是一個會可以幫你的 element 去平方的一個函數。 那名詞是什麼不重要,重要的就是它可以做這個事情。 然後呢 叫它 apply 到 list1 裡面,我們把它傳出值叫做 把它傳到 out2 這個變數裡面,然後把它轉成 list 之後印出來。 那所以它會得到一樣的結果,所以發現就是說呢,用 lambda operator 有些時候呢,就是說它可以讓整個這個 這個你的這個程式呢變得更精簡一些哦 也許變得更可讀,有些人會覺得這樣變得更可讀,有些人覺得不會。 那但是就是說呢,這個是一個這個很多時候你在閱讀別人的 Python 的這個程式的時候,你會看到的東西,那我們在這邊稍微介紹一下,好。 那這個 map 跟 lambda 這個東西呢,就可以應用到我們 前面在算這個 checksum 這個地方嘛哦。 那怎麼做呢?我們來看一下哦,那一樣哦 這個我們現在這個是第三版,所以跟前面也是有一點點不一樣哦。 那所以我們做什麼事情呢,我們就把前面的那個迴圈跟 zip 的那個東西哦,把它代換成這一行。 所以這一行做什麼事情呢,這一行就是它是一個 map 的這個 operator,對不對?好,那它的 map 是要處理什麼呢?是要處理這個 newid 跟 weight zip 起來的那個東西,所以這個 newid 跟 zip 起來的那個東西 呢,我們定義一個新的函數去處理它,這個函數是什麼呢?它 take 一個 pair 之後呢,把這個 pair 的 第一個、 位置 1 的這個元素 跟位置 0 去 int 之後的這個元素呢相乘。 好,然後呢,就 return 回來,那 return 回來的東西擺在 out1。 所以 out1 也會是一個長度為 11 的一個這個資料結構,那這個資料結構裡面呢 就會是每一個位置呢就是是 apply 那個權重之後的結果。 好,那做完這個事情之後呢,就直接把 out1 把它的結果 sum 起來就會是我們 checksum 的結果。 好,大概是這樣子,所以呢,你如果用這個東西下去算哦,這個 check sum 你會得到一樣的信息,所以就是說看起來似乎是 更精簡的一些啦,更精簡的一些,那只是說你喜不喜歡 好,你比較喜歡最早那種做法,還是比較喜歡現在這個做法你可以自己決定,但是就是說 呢,這個 Python 要提供這樣子的一個做法在裡面。 那事實上還有別種做法,我們現在 時間上這個有限制沒有辦法再介紹,但是就是說事實上就在做同一件 事情有不同的做法,那至於怎麼做,這事實上這是你個人的風格跟選擇啦,好。