使用Mathematica,我有一个列表:
l={0,0,0,1,2,0,0,0,1,0,0,0,2,0,0,0}
我想对上面的列表应用一个函数以获得以下内容:
{0,0,0,1,2,2,2,2,1,1,1,1,2,2,2,2}
本质上,我想用相同长度的游程替换0值的游程,但要在每次运行0s之前使用正整数的值。
我以为我可以使用FoldList轻松地做到这一点,但是我看不到解决方案的出路。
非常感谢。
最佳答案
这是您的测试 list :
tst = {0, 0, 0, 1, 2, 0, 0, 0, 1, 0, 0, 0, 2, 0, 0, 0}
以下解决方案将是相当有效的:
In[31]:= Module[{n = 0}, Replace[tst, {0 :> n, x_ :> (n = x)}, {1}]]
Out[31]= {0, 0, 0, 1, 2, 2, 2, 2, 1, 1, 1, 1, 2, 2, 2, 2}
它的工作方式如下:我们使用仅应用第一个匹配规则的事实。变量
n
存储模式匹配器在列表中运行期间遇到的最后一个非零值。最初,它设置为零。第一条规则将0
替换为n
的当前值。如果匹配,则进行替换,然后模式匹配器继续运行。如果不匹配,则我们有一个非零值,第二条规则适用,更新了n
的值。由于Set
赋值返回该值,因此将非零元素简单地放回去。该解决方案的 list 长度应具有线性复杂度,并且是IMO偶尔将副作用与规则混合使用的一个很好的例子。编辑
这是一个功能版本:
In[56]:= Module[{n = 0}, Map[If[# != 0, n = #, n] &, tst]]
Out[56]= {0, 0, 0, 1, 2, 2, 2, 2, 1, 1, 1, 1, 2, 2, 2, 2}
可以检查基于规则的版本对于大型列表的速度大约快4倍。然而,
这种形式的优点是可以很容易地使用
Compile
-d来提供出色的性能:nzrunsC =
Compile[{{l, _Integer, 1}},
Module[{n = 0}, Map[If[# != 0, n = #, n] &, l]],
CompilationTarget -> "C"]
In[68]:= tstLarge = RandomInteger[{0,2},{10000000}];
In[69]:= nzrunsC[tstLarge];//Timing
Out[69]= {0.047,Null}
In[70]:= Module[{n = 0},Map[If[#!=0,n = #,n]&,tstLarge]];//Timing
Out[70]= {18.203,Null}
这里的差异是几百倍,比基于规则的解决方案快一百倍。 OTOH,基于规则的解决方案也适用于符号列表,不一定是整数列表。
关于wolfram-mathematica - 如何将运行中的每个值替换为运行前的整数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6968806/