在Mathematica中使用MapAt中的All

时间:2011-12-20 18:23:13

标签: wolfram-mathematica

我经常有一对配对列表,如

data = {{0,0.0},{1,12.4},{2,14.6},{3,25.1}}

我希望对所有第二个元素执行某些操作,例如Rescale,而不触及第一个元素。我知道的最好方法是:

Transpose[MapAt[Rescale, Transpose[data], 2]]

必须有一种方法可以在没有Transpose的情况下做到这一点。我希望这样的事情能发挥作用:

MapAt[Rescale, data, {All, 2}]

但我的理解是MapAt采用Position - 样式规范而不是Part - 样式规范。什么是正确的解决方案?

澄清,

我正在寻求一个解决方案,我不必重复自己,因此缺少双Transpose或双[[All,2]],因为我认为重复是一个信号,我没有做最简单的事情。但是,如果消除重复需要引入中间变量或命名函数或其他额外的复杂性,则转置/非转置解决方案可能已经正确。

5 个答案:

答案 0 :(得分:10)

使用Part

data = {{0, 0.0}, {1, 12.4}, {2, 14.6}, {3, 25.1}}

data[[All, 2]] = Rescale @ data[[All, 2]];

data

如果需要,请先创建副本。 (data2 = data然后data2[[All, 2]]等。)


修改我的答案以跟上ruebenko的问题,这也可以成为一个功能:

partReplace[dat_, func_, spec__] :=
  Module[{a = dat},
    a[[spec]] = func @ a[[spec]];
    a
  ]

partReplace[data, Rescale, All, 2]

这很普遍就是设计。

答案 1 :(得分:5)

我来参加晚会,我将要描述的内容与@Mr的内容差异很小。向导有,所以最好将此答案视为对其解决方案的补充。我的部分借口是,首先,下面的函数将事情打包得有点不同,更接近MapAt本身的语法,其次,它更通用,可以选择与Listable函数一起使用,第三,我正在复制我过去Mathgroup thread的解决方案,正是这个问题超过了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。 @WhisWizard的解决方案假定函数是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}}

对大型列表进行测试表明,使用可列表性可以提高性能,但在这里并没有那么显着:

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 <\ n>宣布Listable,但我们知道其正文是由{{1}构建的函数,因此它可以应用于整个列表 - 但OTOH不能由Listable自动编译。请注意,向Map添加Listable属性在此处完全错误并且会破坏目的,导致f在两种情况下都变慢。

答案 2 :(得分:3)

怎么样

Transpose[{#[[All, 1]], Rescale[#[[All, 2]]]} &@data]

返回你想要的东西(即它不会改变data

如果不允许Transpose

Thread[Join[{#[[All, 1]], Rescale[#[[All, 2]]]} &@data]]

的工作原理。

编辑:由于“最短”现在是目标,到目前为止我最好的是:

data\[LeftDoubleBracket]All, 2\[RightDoubleBracket] = Rescale[data[[All, 2]]]

,共80个字符,与Mr.Wizard的相同......所以投票给his answer

答案 3 :(得分:2)

这是另一种方法:

op[data_List, fun_] := 
 Join[data[[All, {1}]], fun[data[[All, {2}]]], 2]

op[data, Rescale]

修改1

Mr.Wizard的扩展,不会复制它的数据。

SetAttributes[partReplace, HoldFirst]
partReplace[dat_, func_, spec__] := dat[[spec]] = func[dat[[spec]]];

像这样使用

partReplace[data, Rescale, All, 2]

编辑2 : 或者像这样

ReplacePart[data, {All, 2} -> Rescale[data[[All, 2]]]]

答案 4 :(得分:1)

这适合我和朋友

In[128]:= m = {{x, sss, x}, {y, sss, y}}
Out[128]= {{2, sss, 2}, {y, sss, y}}

In[129]:= function[ins1_] := ToUpperCase[ins1];
fatmap[ins2_] := MapAt[function, ins2, 2];

In[131]:= Map[fatmap, m]
Out[131]= {{2, ToUpperCase[sss], 2}, {y, ToUpperCase[sss], y}}