Если вы знаете, сколько элементов будет иметь ваш результат, и если вы сможете рассчитать свои элементы, тогда весь Append, AppendTo, Linked-List и т. Д. Не требуется.В тесте скорости Криса, предварительное распределение работает только потому, что он заранее знает количество элементов.Операция доступа к datelist означает виртуальное вычисление текущего элемента.
Если бы ситуация была такой, я бы никогда не использовал такой подход.Простой стол в сочетании с объединением - это, черт возьми, быстрее.Позвольте мне повторно использовать код Криса: я добавляю предварительное распределение к измерению времени, потому что при использовании «Добавить» или связанного списка также определяется распределение памяти.Кроме того, я действительно использую полученные списки и проверяю, равны ли они, потому что умный интерпретатор может распознать простые, бесполезные команды и оптимизировать их.
Needs["PlotLegends`"]
test[n_] := Module[{
startlist = Range[1000],
datalist, joinResult, linkedResult, linkinglist, linkedlist,
preallocatedlist, linkedlisttime, preallocatedtime, count,
joinTime, preallocResult},
datalist = RandomReal[1, n*1000];
linkinglist = startlist;
{linkedlisttime, linkedResult} =
AbsoluteTiming[
Do[linkinglist = {linkinglist, datalist[[i]]}, {i,
Length[datalist]}];
linkedlist = Flatten[linkinglist]
];
count = -1;
preallocatedtime = First@AbsoluteTiming[
(preallocatedlist =
Join[startlist, ConstantArray[0, {Length[datalist]}]];
Do[preallocatedlist[[count]] = datalist[[count]];
count--, {Length[datalist]}]
)
];
{joinTime, joinResult} =
AbsoluteTiming[
Join[startlist,
Table[datalist[[i]], {i, 1, Length[datalist]}]]];
PrintTemporary[
Equal @@@ Tuples[{linkedResult, preallocatedlist, joinResult}, 2]];
{preallocatedtime, linkedlisttime, joinTime}];
results = test[#] & /@ Range[40];
ListLinePlot[Transpose[results], PlotStyle -> {Black, Gray, Red},
PlotLegend -> {"Prealloc", "Linked", "Joined"},
LegendPosition -> {1, 0}]
На мой взгляд, интересны ситуации, когда вы заранее не знаете количество элементов и вам нужно решить, неважно, вы или нет.должен добавить / предварять что-то.В этих случаях стоит взглянуть на Рип [] и Соу [].В общем, я бы сказал, AppendTo - это зло, и прежде чем использовать его, взгляните на альтернативы:
n = 10.^5 - 1;
res1 = {};
t1 = First@AbsoluteTiming@Table[With[{y = Sin[x]},
If[y > 0, AppendTo[res1, y]]], {x, 0, 2 Pi, 2 Pi/n}
];
{t2, res2} = AbsoluteTiming[With[{r = Release@Table[
With[{y = Sin[x]},
If[y > 0, y, Hold@Sequence[]]], {x, 0, 2 Pi, 2 Pi/n}]},
r]];
{t3, res3} = AbsoluteTiming[Flatten@Table[
With[{y = Sin[x]},
If[y > 0, y, {}]], {x, 0, 2 Pi, 2 Pi/n}]];
{t4, res4} = AbsoluteTiming[First@Last@Reap@Table[With[{y = Sin[x]},
If[y > 0, Sow[y]]], {x, 0, 2 Pi, 2 Pi/n}]];
{res1 == res2, res2 == res3, res3 == res4}
{t1, t2, t3, t4}
Дает {5.151575, 0.250336, 0.128624, 0.148084}.Конструкция
Flatten@Table[ With[{y = Sin[x]}, If[y > 0, y, {}]], ...]
, к счастью, действительно читабельна и быстра.
Замечание
Будьте осторожны, пытаясь повторить последний пример дома.Здесь, на моем Ubuntu 64bit и Mma 8.0.4, AppendTo с n = 10 ^ 5 занимает 10 ГБ памяти.n = 10 ^ 6 занимает всю мою оперативную память, которая составляет 32 ГБ, чтобы создать массив, содержащий 15 МБ данных.Забавно.