如何在Mathematica中以惯用的方式将每个0替换为列表中的前一个元素?

时间:2011-12-30 18:57:17

标签: wolfram-mathematica

这是一个有趣的小问题,我想与专家一起检查是否有更好的功能/ Mathematica方法来解决它而不是我做的。我对我的解决方案不太满意,因为我在其中使用了大的IF THEN ELSE,但找不到Mathematica命令来轻松使用它(例如SelectCases,{{1} },Sow/Reap ..等...)

给出一个列表值(数字或符号),这是问题,但为简单起见,我们假设现在有一个数字列表。该列表可以包含零,目标是将每个零替换为之前看到的元素。

最后,列表中不应包含零

这是一个例子,给定

Map

结果应该是

a = {1, 0, 0, -1, 0, 0, 5, 0};

应该以最有效的方式进行。

这就是我能想到的

a = {1, 1, 1, -1, -1, -1, 5, 5}

我想知道我是否可以使用Sow / Reap,但不知道如何。

问题:这可以用更实用的/ Mathematica方式解决吗?课程越短越好:)

更新1 谢谢大家的回答,所有这些都是非常好的学习。这是速度测试的结果,在V 8.04上,使用Windows 7,4 GB Ram,intel 930 @ 2.8 Ghz:

我已经测试了从Scan[(a[[#]] = If[a[[#]] == 0, a[[#-1]], a[[#]]]) &, Range[2, Length[a]]]; n的{​​{1}}给出的方法。 100,000方法对大型列表效果不佳。

更新2

删除了上面在update1中显示的结果,因为我在复制其中一个测试时出错。

更新后的结果如下。列昂尼德方法是最快的。祝贺列昂尼德。一种非常快速的方法。

enter image description here

测试程序如下:

4 million

要运行长度为1000的测试,命令为:

ReplaceRepeated

感谢大家的回答。

4 个答案:

答案 0 :(得分:12)

比其他解决方案还要快很多(数量级):

FoldList[If[#2 == 0, #1, #2] &, First@#, Rest@#] &

加速是由Fold自动编译引起的。对于非打包数组,不会那么戏剧化。基准:

In[594]:= 
a=b=c=RandomChoice[Join[ConstantArray[0,10],Range[-1,5]],150000];
(b=Flatten[Accumulate/@Split[b,(#2==0)&]]);//Timing
Scan[(a[[#]]=If[a[[#]]==0,a[[#-1]],a[[#]]])&,Range[2,Length[a]]]//Timing
(c=FoldList[If[#2==0,#1,#2]&,First@#,Rest@#]&@c);//Timing

SameQ[a,b,c]

Out[595]= {0.187,Null}
Out[596]= {0.625,Null}
Out[597]= {0.016,Null}
Out[598]= True

答案 1 :(得分:8)

这似乎是我机器上的一个因素4:

a = Flatten[Accumulate /@ Split[a, (#2 == 0) &]]

我得到的时间是

a = b = RandomChoice[Join[ConstantArray[0, 10], Range[-1, 5]], 10000];

(b = Flatten[Accumulate /@ Split[b, (#2 == 0) &]]); // Timing

Scan[(a[[#]] = If[a[[#]] == 0, a[[# - 1]], a[[#]]]) &, 
  Range[2, Length[a]]] // Timing

SameQ[a, b]

(* {0.015815, Null} *)
(* {0.061929, Null} *)
(* True *)

答案 2 :(得分:8)

FixedPoint[(1 - Unitize[#]) RotateRight[#] + # &, d]

比Heike的解决方案快10倍和2倍,但比Leonid的速度慢。

答案 3 :(得分:6)

您的问题看起来与ReplaceRepeated功能的任务完全相同。它的作用基本上是它将相同的规则集应用于表达式,直到不再适用规则为止。在您的情况下,表达式是一个列表,规则是在列表中发生时将其与其前任替换为0。所以这是解决方案:

a = {1, 0, 0, -1, 0, 0, 5, 0};
a //. {x___, y_, 0, z___} -> {x, y, y, z};

此处规则的模式如下:

  • x___ - 任何符号,零个或多个重复,列表的开头
  • y_ - 正好是零之前的一个元素
  • 0 - 零本身,此元素稍后将替换为y
  • z___ - 任何符号,零个或多个重复,列表的结尾