2011-08-06 52 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

相關問題