开发者

Changing values in nested lists according to elements in the list

I have a list of pairs of values in mathematica, for example 开发者_如何学运维List= {{3,1},{5,4}}.

How do I change the first element (3 & 5) if the second element does not reach a threshold. For example, if the second parts are below 2 then i wish the first parts to go to zero. so that list then = {{0,1},{5,4}}. Some of these lists are extremely long so manually doing it is not an option, unfortunately.


Conceptually, the general way is to use Map. In your case, the code would be

In[13]:= lst = {{3, 1}, {5, 4}}

Out[13]= {{3, 1}, {5, 4}}

In[14]:= thr = 2

Out[14]= 2

In[15]:= Map[{If[#[[2]] < thr, 0, #[[1]]], #[[2]]} &, lst]

Out[15]= {{0, 1}, {5, 4}}

The # symbol here stands for the function argument. You can read more on pure functions here. Double square brackets stand for the Part extraction. You can make it a bit more concise by using Apply on level 1, which is abbreviated by @@@:

In[27]:= {If[#2 < thr, 0, #], #2} & @@@ lst

Out[27]= {{0, 1}, {5, 4}}

Note however that the first method is several times faster for large numerical lists. An even faster, but somewhat more obscure method is this:

In[29]:= Transpose[{#[[All, 1]]*UnitStep[#[[All, 2]] - thr], #[[All, 2]]}] &[lst]

Out[29]= {{0, 1}, {5, 4}}

It is faster because it uses very optimized vectorized operations which apply to all sub-lists at once. Finally, if you want the ultimate performance, this procedural compiled to C version will be another factor of 2 faster:

fn = Compile[{{lst, _Integer, 2}, {threshold, _Real}},
  Module[{copy = lst, i = 1},
    For[i = 1, i <= Length[lst], i++,
      If[copy[[i, 2]] < threshold, copy[[i, 1]] = 0]];
    copy], CompilationTarget -> "C", RuntimeOptions -> "Speed"] 

You use it as

In[32]:= fn[lst, 2] 

Out[32]= {{0, 1}, {5, 4}}

For this last one, you need a C compiler installed on your machine.


Another alternative: Apply (@@@, Apply at level 1) and Boole (turns logical values in 1's and 0's):

lst = {{3, 1}, {5, 4}};
{#1 Boole[#2 >= 2], #2} & @@@ lst


An alternative approach might be to use substitution rules, and attach a condition (/;)

lst = {{3, 1}, {5, 4}};

lst /. {x_, y_ /; y < 2} -> {0, y}

output:

{{0, 1}, {5, 4}}


Assuming that your matrix is 2x2 and by second elemnt you mean the second row: This should work:

If[A[[2, 1]] < 2 || A[[2, 2]] < 2, A[[2,1]] = 0 ]; A

You may have to change the variables, since your questions is kind of confusing. But that's the idea ;-)

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜