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

作者: biglion ( )   2015-01-25 16:07:10
※ 引述《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
作者: chungyuandye (養花種魚數月亮賞星星)   2015-01-25 17:02:00
{#[[1]],Length@#}&/@Split[list,(#1== #2)&]
作者: LPH66 (-6.2598534e+18f)   2015-01-25 20:53:00
Pattern 其實可以說是 Mathematica 運算的核心平常的函數定義及呼叫就是一個 pattern matching 的過程所以 Pattern 用的好確實可以如虎添翼 XD
作者: pig030 (FEBUR.PHEIX)   2015-01-26 20:53:00
太神了,感謝又學到新的用法了^^
作者: carelai (我心依舊)   2015-02-06 18:36:00
對,這其實是Mathematica精妙之所在,Mathematica其實是untyped functional language,和lisp一樣,請問lisp也有類似上面的pattern matching嗎?另外方便和效率是天平的兩端,不可兼得,贊這句話

Links booklink

Contact Us: admin [ a t ] ucptt.com