我经常有一对配对列表,如
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]]
,因为我认为重复是一个信号,我没有做最简单的事情。但是,如果消除重复需要引入中间变量或命名函数或其他额外的复杂性,则转置/非转置解决方案可能已经正确。
答案 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}}