Re: [問題] 如何計算字串中元素出現的頻率

看板Mathematica作者 ( )時間9年前 (2015/01/25 16:07), 編輯推噓2(207)
留言9則, 4人參與, 最新討論串2/2 (看更多)
※ 引述《lambking (BB)》之銘言: : 想要寫一個function 去計算一個字串中某元素出現的次數 : 例如: : list={a,a,b,b,c,c,c,} ; : frequncycount[list] : output: : {{a,2},{b,2},{c,3}} : 請問有什麼方法能夠寫這個function ? : 謝謝 誠如chungyuandye所言 Mathematica內建的Tally指令是這個問題最好最快的解法 Tally甚至還能自訂"相同"元素的比對函數 但如果題目稍微變化一下呢? 像是想以連續相同元素個數對表示一串列 例如將{a,a,a,b,b,a,b,b,b,a,a}變成{{a,3},{b,2},{a,1},{b,3},{a,2}} 該怎麼計算呢? 當然可以用迴圈輕易地達成 不過這就無法發揮Mathematica的長處了 其實這類問題能夠非常直覺地以pattern跟rule解決 這也是Mathematica另一個強大之處 直接寫出原po問題的pattern/rule解法: {#, 1} & /@ list //. {head___, {x_, n_}, mid___, {x_, m_}, tail___} -> {head, mid, tail, {x, n + m}} 這麼直白的程式碼 相信許多人已經了解了其計算原理 一開始的 {#,1} & /@ list 利用純函數轉換原串列 例如{a,b,a,b,c,c,c}將變為{{a,1},{b,1},{a,1},{b,1},{c,1},{c,1},{c,1}} 這邊的 1 就是代表出現次數 接著後面的 //. 表示將持續替換後面的rule直到結果不再變化為止 如果寫的是 /. 那就表示僅替換一次 這裡先點到功能,稍後會說明為什麼要使用 //. 重點來了 後面的rule是這個程式碼的計算核心: {head___, {x_, n_}, mid___, {x_, m_}, tail___} -> {head, mid, tail, {x, n+m}} 簡要介紹一下: head___、mid___、tail___中的三連續底線 表示這些pattern可以匹配任意序列(sequence),並且可為空序列 如果只有2個連續底線也可匹配任意序列,但不包含空序列 至於單一底線,則是匹配任意表示式(expression) 例如其後的x_、n_、m_等 初學者在這邊只要簡單地想像為單一元素即可 仔細看的話會發現箭頭的左邊出現了兩個 x_ 這表示兩個pattern必須匹配相同的元素 而右邊只有出現一次 表示這個rule每作用一次就會減少一項 換句話說,它會合併相同的 x_ 項 並且將其出現次數相加 至於使用head___、mid___、tail___這三個pattern的原因 是為了表示這兩個x_之前、之後、之間可以存在任意序列,包含空序列 只要不斷地重複這個步驟 最後就能得到我們要的結果 這就是要使用 //. 的原因 介紹完這個解法之後,相信各位會覺得這真是太直接了 甚至可以說這個rule同時描述了問題以及解法 這是Mathematica pattern/rule好用之處 可惜的是,方便跟效率經常位於天平的兩端 這個方法的效率並無法與Tally相比 不過在串列不大的情況下,還是挺好用的 行文至此,忍不住要為各位出一道作業 如果將{x,n+m}換個位置: {head___, {x_, n_}, mid___, {x_, m_}, tail___} -> {head,{x,n+m}, mid, tail} 輸出結果是相同的(但順序可能不同) 但效率變得奇差無比 各位可以思考一下原因 回到先前拋出來的問題: 如何以連續相同元素個數對表示一串列 解法非常直覺: {#, 1} & /@ list //.{head___,{x_,n_},{x_,m_},tail___}-> {head, {x, n+m}, tail} 後話 pattern/rule不常被注意 但其實很好用 至於中文參考書籍可參考最近出版的Mathematica Cookbook -- ※ 發信站: 批踢踢實業坊(ptt.cc), 來自: 1.169.212.109 ※ 文章網址: https://www.ptt.cc/bbs/Mathematica/M.1422173233.A.00D.html

01/25 17:02, , 1F
{#[[1]],Length@#}&/@Split[list,(#1== #2)&]
01/25 17:02, 1F

01/25 20:53, , 2F
Pattern 其實可以說是 Mathematica 運算的核心
01/25 20:53, 2F

01/25 20:53, , 3F
平常的函數定義及呼叫就是一個 pattern matching 的過程
01/25 20:53, 3F

01/25 20:54, , 4F
所以 Pattern 用的好確實可以如虎添翼 XD
01/25 20:54, 4F

01/26 20:53, , 5F
太神了,感謝又學到新的用法了^^
01/26 20:53, 5F

02/06 18:36, , 6F
對,這其實是Mathematica精妙之所在,Mathematica其實是
02/06 18:36, 6F

02/06 18:37, , 7F
untyped functional language,和lisp一樣,請問lisp也有
02/06 18:37, 7F

02/06 18:38, , 8F
類似上面的pattern matching嗎?
02/06 18:38, 8F

02/06 18:41, , 9F
另外方便和效率是天平的兩端,不可兼得,贊這句話
02/06 18:41, 9F
文章代碼(AID): #1KnAGn0D (Mathematica)
文章代碼(AID): #1KnAGn0D (Mathematica)