Как удалить лишний {} при отображении функции в список - PullRequest
7 голосов
/ 07 января 2012

Простой вопрос, учитывая список, подобный этому

Clear[a, b, c, d, e, f];
lst = {{a, b}, {c, d}, {e, f}};

, и предположим, что у меня есть функция, определенная следующим образом:

foo[x_,y_]:=Module[{},...]

И я хочу применить эту функцию к списку,поэтому, если я наберу

Map[foo, lst]

Это даст

{foo[{a, b}], foo[{c, d}], foo[{e, f}]}

Я хочу, чтобы оно получилось как

{foo[a, b], foo[c, d], foo[e, f]}

, чтобы оно работало.

Каков наилучший способ сделать это?Предположим, что я не могу изменить определение функции foo [] (скажем, она встроенная)

Теперь я знаю только 2 способа:

Map[foo[#[[1]], #[[2]]] &, lst]
{foo[a, b], foo[c, d], foo[e, f]}

(слишком много работы) или

MapThread[foo, Transpose[lst]]
{foo[a, b], foo[c, d], foo[e, f]}

(меньше печатать, но сначала нужно транспонировать)

Вопрос: Есть ли другие способы улучшить вышесказанное?Я посмотрел на другую Карту и ее друзей и не смог увидеть функцию, которая бы делала это более напрямую, чем то, что у меня есть.

Ответы [ 5 ]

14 голосов
/ 07 января 2012

Вам нужно Apply в Level 1 или краткой форме, @@@

foo@@@lst    
{foo[a, b], foo[c, d], foo[e, f]}
7 голосов
/ 07 января 2012

Один из возможных способов - изменить заголовок каждого элемента lst с List на foo:

foo @@ # & /@ lst
{foo[a, b], foo[c, d], foo[e, f]}
6 голосов
/ 07 января 2012

Просто чтобы сообщить удивительные тесты производительности обоих методов (@@@, @@ # & /@):

        T = RandomReal[{1,100}, {1000000, 2}];

        H[F_Symbol, T_List] := 

                     First@AbsoluteTiming[F @@@ T;]/First@AbsoluteTiming[F @@ # & /@ T;]

        Table[{ToString[F], H[F, T]},  {F, {Plus, Subtract, Times, Divide, Power, Log}}]

Out[3]= {{"Plus",     4.174757}, 
         {"Subtract", 0.2596154}, 
         {"Times",    3.928230}, 
         {"Divide",   0.2674164}, 
         {"Power",    0.3148629},
         {"Log",      0.2986936}}

Эти результаты не случайны, а примерно пропорциональны для очень разных размеров данных.

@@@ примерно в 3-4 раза быстрее для Subtract, Divide, Power, Log, в то время как @@ # & /@ в 4 раза быстрее для Plus и Times, что вызывает другие вопросы что (как можно поверить) может быть немного
уточнена следующая оценка:

 Attributes@{Plus, Subtract, Times, Divide, Power, Log}

Только Plus и Times имеют атрибуты Flat и Orderless, в то время как среди остальных только Power (который кажется там наиболее эффективным) также имеет атрибут OneIdentity.

Редактировать

Надежное объяснение наблюдаемому повышению производительности (благодаря замечаниям Леонида Шифрина) должно идти другим путем.

По умолчанию MapCompileLength -> 100, так как мы можем проверить оценку SystemOptions["CompileOptions"]. Для сброса автокомпиляции карты мы можем оценить:

SetSystemOptions["CompileOptions" -> "MapCompileLength" -> Infinity]

Теперь мы можем проверить относительную производительность обоих методов, еще раз оценив нашу H - функцию тестирования производительности для связанных символов и списка:

          Table[{ToString[F], H[F, T]}, {F, {Plus, Subtract, Times, Divide, Power, Log}}]

 Out[15]= {{"Plus",      0.2898246},
           {"Subtract",  0.2979452}, 
           {"Times",     0.2721893}, 
           {"Divide",    0.3078512}, 
           {"Power",     0.3321622},
           {"Log",       0.3258972}}

Имея эти результаты, мы можем заключить, что в целом подход Йоды (@@@) наиболее эффективен, в то время как предложенный Андреем лучше в случае Plus и Times из-за автоматической компиляции Map, позволяющей лучшая производительность (@@ # & /@).

4 голосов
/ 07 января 2012

Еще несколько возможностей для выбора:

Это более подробный вариант ответа йоды.Применяется foo на уровне 1 списка lst только (заменяет голову List на голову foo):

Apply[foo, lst, {1}]

Это делает то же самое, но отображает Apply поверхсписок lst (по сути, ответ Андрея):

Map[Apply[foo, #] &, lst ]

И это просто заменяет шаблон List [x__] на foo [x] на уровне 1:

Replace[lst, List[x__] -> foo[x], 1]
3 голосов
/ 07 января 2012

Ответы на Apply[] точны, и это правильное решение, но то, что вы пытались сделать, - это заменить List[] голову на Sequence[] голову, то есть List[List[3,5],List[6,7]] должно статьList[Sequence[3,5],Sequence[6,7]].

Заголовок последовательности - это то, что естественно остается, если заголовок любого списка параметров удаляется, поэтому Delete[Plus[3,5],0], Delete[{3,5},0] и Delete[List[3,5],0] все приведут к Sequence[3,5].

Так что foo@Delete[#,0]&/@{{a, b}, {c, d}, {e, f}} даст вам то же, что и foo@@@{{a, b}, {c, d}, {e, f}}.

В качестве альтернативы, foo[#/.List->Sequence]&/@{{a, b}, {c, d}, {e, f}} делает то же самое.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...