Using All in MapAt in Mathematica

前端 未结 5 1587
时光取名叫无心
时光取名叫无心 2021-02-20 02:28

I often have a list of pairs, as

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

and I want to do something, for instance Rescale, to al

相关标签:
5条回答
  • 2021-02-20 03:14

    I am coming late to the party, and what I will describe will differ very little with what @Mr. Wizard has, so it is best to consider this answer as a complementary to his solution. My partial excuses are that first, the function below packages things a bit differently and closer to the syntax of MapAt itself, second, it is a bit more general and has an option to use with Listable function, and third, I am reproducing my solution from the past Mathgroup thread for exactly this question, which is more than 2 years old, so I am not plagiarizing :)

    So, here is the function:

    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]; 
    

    This is the same idea as what @Mr. Wizard used, with these differences: 1. In case when the spec is not of the prescribed form, regular MapAt will be used automatically 2. Not all functions are Listable. The solution of @Mr.Wizard assumes that either a function is Listable or we want to apply it to the entire list. In the above code, you can specify this by the MappedListable option.

    I will also borrow a few examples from my answer in the above-mentioned thread:

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

    Testing on large lists shows that using Listability improves the performance, although not so dramatically here:

    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}
    

    This is likely because for the above function (#/10&), Map (which is used internally in mapAt for the MappedListable->False (default) setting, was able to auto-compile. In the example below, the difference is more substantial:

    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}
    

    The point is that, while f was not declared Listable, we know that its body is built out of Listable functions, and thus it can be applied to the entire list - but OTOH it can not be auto-compiled by Map. Note that adding Listable attribute to f would have been completely wrong here and would destroy the purpose, leading to mapAt being slow in both cases.

    0 讨论(0)
  • 2021-02-20 03:16

    Use Part:

    data = {{0, 0.0}, {1, 12.4}, {2, 14.6}, {3, 25.1}}
    
    data[[All, 2]] = Rescale @ data[[All, 2]];
    
    data
    

    Create a copy first if you need to. (data2 = data then data2[[All, 2]] etc.)


    Amending my answer to keep up with ruebenko's, this can be made into a function also:

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

    This is quite general is design.

    0 讨论(0)
  • 2021-02-20 03:16

    Here is another approach:

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

    Edit 1:

    An extension from Mr.Wizard, that does not copy it's data.

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

    used like this

    partReplace[data, Rescale, All, 2]
    

    Edit 2: Or like this

    ReplacePart[data, {All, 2} -> Rescale[data[[All, 2]]]]
    
    0 讨论(0)
  • 2021-02-20 03:22

    This worked for me and a friend

    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}}
    
    0 讨论(0)
  • 2021-02-20 03:28

    How about

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

    which returns what you want (ie, it does not alter data)

    If no Transpose is allowed,

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

    works.

    EDIT: As "shortest" is now the goal, best from me so far is:

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

    at 80 characters, which is identical to Mr.Wizard's... So vote for his answer.

    0 讨论(0)
提交回复
热议问题