no competir con otras respuestas, pero simplemente no podía dejar de compartir un Compile
(?) - solución basada. La solución se basa en construir un árbol de búsqueda binario y luego verificar cada número en la lista, independientemente de si su índice en la lista es el utilizado para construir el árbol b. Si es así, es el número original, si no, es un duplicado. Lo que hace que esta solución sea interesante para mí es que muestra una forma de emular "pass-by-reference" con Compile
. El punto es que, si incorporamos funciones compiladas en otras funciones compiladas (y eso se puede lograr con una opción "InlineCompiledFunctions"), podemos referirnos en funciones internas a las variables definidas en el alcance de función externo (debido a la forma en que entra en funcionamiento) .Esta no es una verdadera referencia de paso a paso, pero aún permite combinar funciones de bloques más pequeños, sin penalización de eficiencia (esto es más en el espíritu de macroexpulsión). No creo que esto esté documentado, y no tengo idea de si esto permanecerá en futuras versiones. De todas formas, aquí está el código:
(* A function to build a binary tree *)
Block[{leftchildren , rightchildren},
makeBSearchTree =
Compile[{{lst, _Real, 1}},
Module[{len = Length[lst], ctr = 1, currentRoot = 1},
leftchildren = rightchildren = Table[0, {Length[lst]}];
For[ctr = 1, ctr <= len, ctr++,
For[currentRoot = 1, lst[[ctr]] != lst[[currentRoot]],(*
nothing *),
If[lst[[ctr]] < lst[[currentRoot]],
If[leftchildren[[currentRoot]] == 0,
leftchildren[[currentRoot]] = ctr;
Break[],
(* else *)
currentRoot = leftchildren[[currentRoot]] ],
(* else *)
If[rightchildren[[currentRoot]] == 0,
rightchildren[[currentRoot]] = ctr;
Break[],
(* else *)
currentRoot = rightchildren[[currentRoot]]]]]];
], {{leftchildren, _Integer, 1}, {rightchildren, _Integer, 1}},
CompilationTarget -> "C", "RuntimeOptions" -> "Speed",
CompilationOptions -> {"ExpressionOptimization" -> True}]];
(* A function to query the binary tree and check for a duplicate *)
Block[{leftchildren , rightchildren, lst},
isDuplicate =
Compile[{{index, _Integer}},
Module[{currentRoot = 1, result = True},
While[True,
Which[
lst[[index]] == lst[[currentRoot]],
result = index != currentRoot;
Break[],
lst[[index]] < lst[[currentRoot]],
currentRoot = leftchildren[[currentRoot]],
True,
currentRoot = rightchildren[[currentRoot]]
]];
result
],
{{leftchildren, _Integer, 1}, {rightchildren, _Integer,
1}, {lst, _Real, 1}},
CompilationTarget -> "C", "RuntimeOptions" -> "Speed",
CompilationOptions -> {"ExpressionOptimization" -> True}
]];
(* The main function *)
Clear[deldup];
deldup =
Compile[{{lst, _Real, 1}},
Module[{len = Length[lst], leftchildren , rightchildren ,
nodup = Table[0., {Length[lst]}], ndctr = 0, ctr = 1},
makeBSearchTree[lst];
For[ctr = 1, ctr <= len, ctr++,
If[! isDuplicate [ctr],
++ndctr;
nodup[[ndctr]] = lst[[ctr]]
]];
Take[nodup, ndctr]], CompilationTarget -> "C",
"RuntimeOptions" -> "Speed",
CompilationOptions -> {"ExpressionOptimization" -> True,
"InlineCompiledFunctions" -> True,
"InlineExternalDefinitions" -> True}];
Estas son algunas pruebas:
In[61]:= intTst = [email protected][{0,500000},1000000];
In[62]:= (res1 = deldup[intTst ])//Short//Timing
Out[62]= {1.141,{260172.,421188.,487754.,259397.,<<432546>>,154340.,295707.,197588.,119996.}}
In[63]:= (res2 = Tally[intTst,Equal][[All,1]])//Short//Timing
Out[63]= {0.64,{260172.,421188.,487754.,259397.,<<432546>>,154340.,295707.,197588.,119996.}}
In[64]:= res1==res2
Out[64]= True
no tan rápido como la versión Tally
, sino también Equal
- basado, y como he dicho, mi punto era ilustrar una técnica interesante (IMO).
@Michael: Prefiero usar 'DeleteDuplicates [..., Equal]', dado que los números en cuestión son reales, y la comparación predeterminada es 'SameQ'. Mucho más lento, pero más robusto. –
De hecho, una buena sugerencia! –
hmm, siempre me olvido de los complementos como 'DeleteDuplicates'. Por lo que vale, como un built-in en carreras de 3 a 6 veces más rápido en ~ 10^6 elementos que 'unsortedUnion' en mi respuesta. (Tenga en cuenta que esto está usando 'SameQ' no' Equal'.) – rcollyer