ReplaceRepeated
использует SameQ
, чтобы определить, когда прекратить применять правило.
Когда SameQ
сравнивает два списка, он проверяет длины и, если они совпадают, затем применяет SameQ
к элементам изс первого по последнее.В случае left
первый элемент является целым числом, поэтому легко обнаружить отдельные списки, в то время как для списка right
первый элемент является глубоко вложенным выражением, поэтому ему необходимо пройти его.Это причина медлительности.
In[25]:= AbsoluteTiming[
Do[Extract[right, ConstantArray[1, k]] ===
Extract[right, ConstantArray[1, k + 1]], {k, 0, 15000 - 1}]]
Out[25]= {11.7091708, Null}
Теперь сравните это с:
In[31]:= Timing[i = 0; right //. {tail_, head_} :> (i++; tail); i]
Out[31]= {5.351, 15000}
РЕДАКТИРОВАТЬ В ответ на вопрос о возможностях Mr.Wizardчтобы ускорить это.Нужно написать кастомное же тестирование.
ReplaceRepeated
не предоставляет такой опции, поэтому мы должны использовать
FixedPoint
и
ReplaceAll
:
In[61]:= Timing[i = 0;
FixedPoint[(# /. {tail_, _} :> (i++; tail)) &, right,
SameTest ->
Function[
If[ListQ[#1] && ListQ[#2] &&
Length[#1] ==
Length[#2], (#1 === {} && #2 === {}) || (Last[#1] ===
Last[#2]), #1 === #2]]]; i]
Out[61]= {0.343, 15000}
EDIT2 : еще быстрее:
In[162]:= Timing[i = 0;
NestWhile[Function[# /. {tail_, head_} :> (i++; tail)], right,
Function[# =!= {}]]; i]
Out[162]= {0.124, 15000}