如何用运行前的整数替换运行中的每个值 [英] How do I replace each value in run with the integer preceding the run
问题描述
使用 Mathematica,我有一个列表:
Using Mathematica, I have a list:
l={0,0,0,1,2,0,0,0,1,0,0,0,2,0,0,0}
我想对上面的列表应用一个函数来获得以下内容:
I want to apply a function to the above list to obtain the following:
{0,0,0,1,2,2,2,2,1,1,1,1,2,2,2,2}
本质上,我想用相同长度的运行替换 0 值的运行,但使用每次运行 0 之前的正整数值.
Essentially I want to replace the runs of 0 values with runs of the same length, but using the value of the positive integer just preceding each run of 0s.
我以为我可以使用 FoldList 轻松完成此操作,但我无法找到解决方案.
I thought I could do this easily with FoldList, but I can't see my way through to a solution.
非常感谢.
推荐答案
这是您的测试列表:
tst = {0, 0, 0, 1, 2, 0, 0, 0, 1, 0, 0, 0, 2, 0, 0, 0}
以下解决方案将相当有效:
The following solution will be reasonably efficient:
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
赋值返回值,非零元素被简单地放回原处.解决方案应该在列表的长度上具有线性复杂性,并且 IMO 是偶尔将副作用与规则混合使用的一个很好的例子.
The way it works is the following: we use the fact that only the first matching rule is applied. The variable n
stores the last non-zero value encountered by the pattern-matcher during its run through the list. Initially it is set to zero. The first rule replaces 0
with the current value of n
. If it matches, replacement is made and the pattern-matcher goes on. If it does not match, then we have a non-zero value and the second rule applies, updating the value of n
. Since the Set
assignment returns back the value, the non-zero element is simply placed back. The solution should have a linear complexity in the length of the list, and is IMO a good example of the occasional utility of side effects mixed with rules.
编辑
这是一个功能版本:
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,提供极致的性能:
One can check that the rule - based version is about 4 times faster for really large lists. However,
the advantage of this form is that it can easily be Compile
-d, providing extreme performance:
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,基于规则的解决方案也适用于符号列表,不一定是整数列表.
The difference is several hundred times here, and about a hundred times faster than the rule-based solution. OTOH, rule-based solution will work also with symbolic lists, not necessarily integer lists.
这篇关于如何用运行前的整数替换运行中的每个值的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!