2011-08-06 28 views
9

前更换运行中每个值,我有一个列表:如何与整数运行使用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值,但使用正好在每次运行0之前的正整数的值。

我想我可以用FoldList做到这一点很容易,但我看不到我的方式,通过一个解决方案。

非常感谢。

回答

11

这里是你的测试列表:

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存储通过列表的运行期间通过模式匹配器遇到的最后一个非零值。最初它被设置为零。第一条规则取代0n当前值。如果匹配,则进行替换并且模式匹配器继续。如果不匹配的话,我们有一个非零值,第二条规则适用,更新的n值。由于Set赋值返回值,所以非零元素简单放回。该解决方案应该在列表长度上具有线性复杂性,并且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,基于规则的解决方案也可以与符号列表一起工作,不一定是整数列表。

+0

你能解释一下你的解决方案吗?我发现它可行,但我不确定我是否理解'{0:> n,x_:>(n = x)},{1}]' – DavidC

+0

@Leonid这也会覆盖长度为1的零运行。我不确定OP是否认为他们是这样的。 – Sasha

+1

@David - 请参阅更新,我添加了一个解释。你也可以使用'ReplaceAll',但是你必须使用'{0:> n,x_Integer:>(n = x)}'(否则'x_'会匹配整个列表,因为'ReplaceAll'起作用从表达到其部分),这会稍微降低性能。 –

7

ReplaceRepeated似乎对这项工作很好:

l //. {f__, x_ /; x != 0, 0, e___} :> {f, x, x, e} 

(* {0, 0, 0, 1, 2, 2, 2, 2, 1, 1, 1, 1, 2, 2, 2, 2} *) 
+0

大卫,我得到原来的名单回来。我会毫不犹豫地承认,我不知道为什么它应该起作用,但是在你的模式中是否有错误? – rcollyer

+1

@recollyer嗯。适用于我。我检查了代码,看看是否可能粘贴错误。但不是。这正是我跑的。而输出正是我得到的! – DavidC

+1

@Leonid你对表演绝对正确。顺便说一句,对于一万个0,1,2的“随机”列表,我的例程花了1.25s。你的花费是0.0067s。 – DavidC

7

你在下面的优雅的解决方案使用FoldList结果最初的想法:

In[1]:= tst = {0, 0, 0, 1, 2, 2, 0, 0, 0, 1, 0, 0, 0, 2, 0, 0, 0}; 

In[2]:= FoldList[If[#2 != 0, #2, #1] &, 0, tst] // Rest     

Out[2]= {0, 0, 0, 1, 2, 2, 2, 2, 2, 1, 1, 1, 1, 2, 2, 2, 2} 

该解决方案在功能上更加纯净,因为它不需要辅助变量被设置为一个副作用,如基于规则的或基于地图的版本。它也更快:

In[3]:= tstLarge = RandomInteger[{0, 2}, {10000000}]; 

In[4]:= Module[{n = 0}, Replace[tstLarge, {0 :> n, x_ :> (n = x)}, {1}]]; // Timing 

Out[4]= {5.704, Null} 

In[5]:= Module[{n = 0}, Map[If[# != 0, n = #, n] &, tstLarge]]; // Timing 

Out[5]= {16.5619, Null} 

In[6]:= FoldList[If[#2 != 0, #2, #1] &, 0, tstLarge] // Rest; // Timing 

Out[6]= {1.25148, Null} 
+1

很好的解决方案! +1 –

+0

有趣的是它如何工作。 +1 – DavidC

+0

@sakra - 确实非常酷! – Jagra

相关问题