2012-01-11 82 views
4

說我有一個矩陣,看起來是這樣的:如何選擇基於部分字符串匹配Mathematica中

{{foobar, 77},{faabar, 81},{foobur, 22},{faabaa, 8}, 
{faabian, 88},{foobar, 27}, {fiijii, 52}} 

和列表如下:

{foo, faa} 

現在我想根據列表中字符串的部分匹配將矩陣中每行的數字加起來,以便我以此結束:

{{foo, 126},{faa, 177}} 

我假設我需要映射一個Select命令,但我不太確定如何去做,只匹配部分字符串。有誰能夠幫助我?現在我的真實矩陣大約有150萬行,所以不太慢的東西會帶來附加價值。

回答

2

這是另一種方法。它速度相當快,而且簡潔。

data = 
{{"foobar", 77}, 
    {"faabar", 81}, 
    {"foobur", 22}, 
    {"faabaa", 8}, 
    {"faabian", 88}, 
    {"foobar", 27}, 
    {"fiijii", 52}}; 

match = {"foo", "faa"}; 

f = {#2, Tr @ Pick[#[[All, 2]], StringMatchQ[#[[All, 1]], #2 <> "*"]]} &; 

f[data, #]& /@ match 
{{"foo", 126}, {"faa", 177}}

您可以使用ruebenko的前處理中更快的速度。
這是關於快兩倍,他在我的系統方法:

{str, vals} = Transpose[data]; 
vals = Developer`ToPackedArray[vals]; 

f2 = {#, Tr @ Pick[vals, StringMatchQ[str, "*" <> # <> "*"]]} &; 

f2 /@ match 

注意,在這個版本我測試子不在開頭,以配合ruebenko的輸出。如果你只想匹配字符串的開頭,這是我在第一個函數中所假設的,它仍然會更快。

+0

我喜歡它。快速,靈活,正是我所需要的。 – 2012-01-12 16:16:28

3

這裏是一個起點:

data={{"foobar",77},{"faabar",81},{"foobur",22},{"faabaa",8},{"faabian",88},{"foobar",27},{"fiijii",52}}; 

{str,vals}=Transpose[data]; 
vals=Developer`ToPackedArray[vals]; 
findValPos[str_List,strPat_String]:= 
    Flatten[Developer`ToPackedArray[ 
     Position[StringPosition[str,strPat],Except[{}],{1},Heads->False]]] 

Total[vals[[findValPos[str,"faa"]]]] 
1

使數據

mat = {{"foobar", 77}, 
    {"faabar", 81}, 
    {"foobur", 22}, 
    {"faabaa", 8}, 
    {"faabian", 88}, 
    {"foobar", 27}, 
    {"fiijii", 52}}; 
lst = {"foo", "faa"}; 

現在選擇

r1 = Select[mat, StringMatchQ[lst[[1]], StringTake[#[[1]], 3]] &]; 
r2 = Select[mat, StringMatchQ[lst[[2]], StringTake[#[[1]], 3]] &]; 
{{lst[[1]], [email protected][[All, 2]]}, {lst[[2]], [email protected][[All, 2]]}} 

{{"foo", 126}, {"faa", 177}} 

我會盡量做到更多的功能/一般如果我能...

編輯(1)

下面這使得它更普遍。 (使用相同的數據同上):

foo[mat_, lst_] := Select[mat, StringMatchQ[lst, StringTake[#[[1]], 3]] &] 
r = Map[foo[mat, #] &, lst]; 
MapThread[ {#1, Total[#2[[All, 2]]]} &, {lst, r}] 

給上述

{{"foo", 126}, {"faa", 177}} 

所以現在相同的代碼將工作,如果LST改爲3項,而不是2:

lst = {"foo", "faa", "fii"}; 
1

怎麼樣:

list = {{"foobar", 77}, {"faabar", 81}, {"foobur", 22}, {"faabaa", 
    8}, {"faabian", 88}, {"foobar", 27}, {"fiijii", 52}}; 

t = StringTake[#[[1]], 3] &; 

{t[#[[1]]], Total[#[[All, 2]]]} & /@ SplitBy[SortBy[list, t], t] 

{{"faa", 177}, {"fii", 52}, {"foo", 126}} 

我確定我有閱讀一篇文章,也許在這裏,其中有人描述了一個功能,有效地結合了排序和分裂,但我不記得它。也許其他人可以添加評論,如果他們知道它。

編輯

確定必須睡覺 - 我怎能忘了Gatherby

{t[#[[1]]], Total[#[[All, 2]]]} & /@ GatherBy[list, t] 

{{"foo", 126}, {"faa", 177}, {"fii", 52}} 

注意,對於140萬對的假名單這花了幾秒鐘,所以不完全是一個超級快速的方法。

+0

剛發現在發佈一個基於'GatherBy'的答案後,您的請求發表了評論,並且您在睡前記住了它。刪除我的答案..對於一個小泛化,你可以讓't'帶一個參數't [k _] = StringTake [@ [[1]],k]%'。 (+1) – kglr 2012-01-11 12:20:44