Как выбрать на основе частичного совпадения строк в Mathematica - PullRequest
4 голосов
/ 11 января 2012

Скажем, у меня есть матрица, которая выглядит примерно так:

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

и такой список:

{foo, faa}

Теперь я хотел бы сложить числа для каждой строкив матрице, основанной на частичном совпадении строк в списке, поэтому я получаю следующее:

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

Я предполагаю, что мне нужно отобразить команду Select, но я не совсем уверен, как это сделать.это и соответствует только частичной строке.Кто-нибудь может мне помочь?Теперь моя настоящая матрица составляет около 1,5 миллионов строк, поэтому что-то не слишком медленное принесло бы дополнительную ценность.

Ответы [ 4 ]

3 голосов
/ 11 января 2012

Вот отправная точка:

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"]]]]
2 голосов
/ 12 января 2012

Вот еще один подход. Это достаточно быстро, а также кратко.

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. Если вы хотите сопоставлять только в начале строки, что я и предполагал в первой функции, это будет еще быстрее.

1 голос
/ 11 января 2012

Как насчет:

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}}

Обратите внимание, что для фиктивного списка из 1,4 миллиона пар это заняло пару секунд, поэтому это не совсем быстрый метод.

1 голос
/ 11 января 2012

сделать данные

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}}

Я постараюсь сделать его более функциональным / общим, если смогу...

edit (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"};
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...