如何根据Mathematica中的部分字符串匹配进行选择

时间:2012-01-11 10:38:31

标签: string wolfram-mathematica

假设我有一个看起来像这样的矩阵:

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

和这样的列表:

{foo, faa}

现在我想基于列表中字符串的部分匹配来添加矩阵中每一行的数字,以便我最终得到:

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

我假设我需要映射一个Select命令,但我不太清楚如何做到并只匹配部分字符串。有谁能够帮我?现在我的真实矩阵大约有150万行,所以不太慢的东西会增加价值。

4 个答案:

答案 0 :(得分: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 :(得分: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的输出。如果你只想在字符串的开头匹配,这是我在第一个函数中假设的那样,它会更快。

答案 2 :(得分: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]], Total@r1[[All, 2]]}, {lst[[2]], Total@r2[[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"};

答案 3 :(得分: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万对的虚拟列表,这需要几秒钟,因此不是一个超快的方法。