Я опаздываю на вечеринку, и то, что я опишу, будет очень мало отличаться от того, что @Mr. Мастер имеет, так что лучше всего рассматривать этот ответ как дополнение к своему решению. Я частично оправдываю это тем, что, во-первых, нижеприведенная функция упаковывает вещи немного по-другому и ближе к синтаксису самого MapAt
, во-вторых, она немного более общая и имеет возможность использовать функцию Listable
, а в-третьих, я я воспроизводю свое решение из прошлой темы Mathgroup именно для этого вопроса, которому более 2 лет, поэтому я не плагиат :))
Итак, вот функция:
ClearAll[mapAt,MappedListable];
Protect[MappedListable];
Options[mapAt] = {MappedListable -> False};
mapAt[f_, expr_, {pseq : (All | _Integer) ..}, OptionsPattern[]] :=
Module[{copy = expr},
copy[[pseq]] =
If[TrueQ[OptionValue[MappedListable]] && Head[expr] === List,
f[copy[[pseq]]],
f /@ copy[[pseq]]
];
copy];
mapAt[f_, expr_, poslist_List] := MapAt[f, expr, poslist];
Это та же идея, что и @Mr. Используется мастер с такими отличиями: 1. В случае, если спецификация не имеет предписанной формы, автоматически будет использоваться обычный MapAt
2. Не все функции Listable
. Решение @ Mr.Wizard предполагает, что либо функция имеет значение Listable
, либо мы хотим применить ее ко всему списку. В приведенном выше коде вы можете указать это с помощью опции MappedListable
.
Я также позаимствую несколько примеров из моего ответа в вышеупомянутой теме:
In[18]:= mat=ConstantArray[1,{5,3}];
In[19]:= mapAt[#/10&,mat,{All,3}]
Out[19]= {{1,1,1/10},{1,1,1/10},{1,1,1/10},{1,1,1/10},{1,1,1/10}}
In[20]:= mapAt[#/10&,mat,{3,All}]
Out[20]= {{1,1,1},{1,1,1},{1/10,1/10,1/10},{1,1,1},{1,1,1}}
Тестирование больших списков показывает, что использование Listability повышает производительность, хотя и не так резко:
In[28]:= largemat=ConstantArray[1,{150000,15}];
In[29]:= mapAt[#/10&,largemat,{All,3}];//Timing
Out[29]= {0.203,Null}
In[30]:= mapAt[#/10&,largemat,{All,3},MappedListable->True];//Timing
Out[30]= {0.094,Null}
Вероятно, это связано с тем, что для вышеуказанной функции (#/10&
) Map
(которая используется внутри mapAt
для настройки MappedListable->False
(по умолчанию)) удалось автоматически скомпилировать. В приведенном ниже примере Разница более существенная:
ClearAll[f];
f[x_] := 2 x - 1;
In[54]:= mapAt[f,largemat,{All,3}];//Timing
Out[54]= {0.219,Null}
In[55]:= mapAt[f,largemat,{All,3},MappedListable->True];//Timing
Out[55]= {0.031,Null}
Дело в том, что в то время как f
было не объявлено Listable
, мы знаем , что его тело состоит из Listable
функций, и, таким образом, оно может быть применяется ко всему списку - но OTOH он не может быть автоматически скомпилирован Map
. Обратите внимание, что добавление атрибута Listable
к f
было бы совершенно неверным и разрушило бы цель, что привело к замедлению mapAt
в обоих случаях.