Как заменить каждый 0 предыдущим элементом в списке идиоматическим способом в системе Mathematica?

Это небольшая забавная задача, и я хотел узнать у экспертов, есть ли лучший функциональный / математический подход к ее решению, чем то, что я сделал. Я не очень доволен своим решением, поскольку я использую в нем большое значение IF THEN ELSE, но не могу найти команду Mathematica, которую можно было бы легко использовать для этого (например, Select , Cases , Sow / Reap , Map ... и т. Д. ...)

Вот проблема, учитывая значения списка (числа или символы), но для простоты давайте предположим, что список номеров на данный момент. Список может содержать нули, и цель состоит в том, чтобы заменить каждый ноль предыдущим элементом.

В конце список не должен содержать нулей .

Вот пример, учитывая

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

, результат должен быть

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

Конечно, это должно быть сделано наиболее эффективным способом.

Это то, что я мог придумать.

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

Я хотел посмотреть, смогу ли я использовать Sow / Reap, но не знал, как это сделать.

вопрос: можно ли решить эту проблему более функциональным / математическим способом? Конечно, чем короче, тем лучше :)

обновление 1 Спасибо всем за ответ, всем очень приятно учиться. Это результат теста скорости на V 8.04 с использованием Windows 7, 4 ГБ ОЗУ, Intel 930 @ 2.8 ГГц:

Я проверил методы, приведенные для n от 100000 до 4 миллионов . Метод ReplaceRepeated не подходит для больших списков.

update 2

Удален предыдущий результат, который был показан выше в update1 из-за моей ошибки при копировании одного из тестов.

Обновленные результаты приведены ниже. Метод Леонида самый быстрый. Поздравление Леонид. Очень быстрый способ.

enter image description here

Тестовая программа выглядит следующим образом:

(*version 2.0 *)
runTests[sizeOfList_?(IntegerQ[#] && Positive[#] &)] := 
 Module[{tests, lst, result, nasser, daniel, heike, leonid, andrei, 
   sjoerd, i, names},

  nasser[lst_List] := Module[{a = lst},
    Scan[(a[[#]] = If[a[[#]] == 0, a[[# - 1]], a[[#]]]) &, 
     Range[2, Length[a]]]
    ];

  daniel[lst_List] := Module[{replaceWithPrior},
    replaceWithPrior[ll_, n_: 0] := 
     Module[{prev}, Map[If[# == 0, prev, prev = #] &, ll]
      ];
    replaceWithPrior[lst]
    ];

  heike[lst_List] := Flatten[Accumulate /@ Split[lst, (#2 == 0) &]];

  andrei[lst_List] := Module[{x, y, z},
    ReplaceRepeated[lst, {x___, y_, 0, z___} :> {x, y, y, z}, 
     MaxIterations -> Infinity]
    ];

  leonid[lst_List] := 
   FoldList[If[#2 == 0, #1, #2] &, First@#, Rest@#] & @lst;

  sjoerd[lst_List] := 
   FixedPoint[(1 - Unitize[#]) RotateRight[#] + # &, lst];

  lst = RandomChoice[Join[ConstantArray[0, 10], Range[-1, 5]], 
    sizeOfList];
  tests = {nasser, daniel, heike, leonid, sjoerd};
  names = {"Nasser","Daniel", "Heike", "Leonid", "Sjoerd"};

  result = Table[0, {Length[tests]}, {2}];

  Do[
   result[[i, 1]] = names[[i]];

   Block[{j, r = Table[0, {5}]},
    Do[
     r[[j]] = First@Timing[tests[[i]][lst]], {j, 1, 5}
     ];
    result[[i, 2]] = Mean[r]
    ],

   {i, 1, Length[tests]}
   ];

  result
  ]

Чтобы запустить тесты для длины 1000, команда:

Grid[runTests[1000], Frame -> All]

Спасибо всем за ответы.

9
задан Nasser 1 January 2012 в 05:43
поделиться