Using All in MapAt in Mathematica

前端 未结 5 1601
时光取名叫无心
时光取名叫无心 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.

提交回复
热议问题