Это небольшая забавная задача, и я хотел узнать у экспертов, есть ли лучший функциональный / математический подход к ее решению, чем то, что я сделал. Я не очень доволен своим решением, поскольку я использую в нем большое значение 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 из-за моей ошибки при копировании одного из тестов.
Обновленные результаты приведены ниже. Метод Леонида самый быстрый. Поздравление Леонид. Очень быстрый способ.
Тестовая программа выглядит следующим образом:
(*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]
Спасибо всем за ответы.