根据列表中的元素更改嵌套列表中的值

Mar*_*ary 3 wolfram-mathematica

例如,我在mathematica中有一对值列表List= {{3,1},{5,4}}.

如果第二个元素未达到阈值,如何更改第一个元素(3和5).例如,如果第二部分低于2,那么我希望第一部分变为零.所以列表然后= {{0,1},{5,4}}.其中一些列表非常长,所以不幸的是,手动执行它不是一个选项.

Leo*_*rin 9

从概念上讲,一般的方法是使用Map.在你的情况下,代码将是

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}}
Run Code Online (Sandbox Code Playgroud)

#这里的符号代表函数参数.你可以阅读更多关于纯函数这里.双方括号代表零件提取.您可以通过在级别1上使用Apply来使其更简洁 ,其缩写为@@@:

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

Out[27]= {{0, 1}, {5, 4}}
Run Code Online (Sandbox Code Playgroud)

但请注意,对于大型数字列表,第一种方法要快几倍.这是一个更快,但更隐蔽的方法:

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

Out[29]= {{0, 1}, {5, 4}}
Run Code Online (Sandbox Code Playgroud)

它更快,因为它使用非常优化的矢量化操作,一次应用于所有子列表.最后,如果你想要最终性能,这个编译为C版本的程序将是另一个更快的因素:

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"] 
Run Code Online (Sandbox Code Playgroud)

你用它作为

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

Out[32]= {{0, 1}, {5, 4}}
Run Code Online (Sandbox Code Playgroud)

对于最后一个,您需要在计算机上安装C编译器.

  • @Leonid我已经了解到,仔细阅读你的回复是有利的:-)纯粹为了我自己的信息,`{If [#[[2]] <2,0,#[[1]]是否有任何优势],#[[2]]}&/ @ lst`(你的方法)超过`如果[#[[2]] <2,{0,#[[2]]},#]和/ @ lst`? (3认同)
  • @TomD我认为你建议的代码比我的好.它更直接,也快20%.如果你想要速度,IMO最重要的是在`Map`中使用`Compile`-able函数.如果列表的长度超过设置`SystemOptions ["CompileOptions" - >"MapCompileLength"]`,默认为'100`,`Map`会尝试自动编译要映射的函数.我们的两个函数都可以"编译",因此速度很快.但是如果你用模式定义相同的函数并尝试在Map中使用它,你就会立即在打包列表上减慢一个数量级.可以是一个惊喜:) (2认同)