Eliminar duplicados después de n ocurrencias
Como generalización DeleteDuplicates
, quiero eliminar los duplicados de una lista, pero solo después de una n
cantidad de duplicados.
Digamos, n = 3
significa que se permiten tres duplicados.
Hice mi propia función:
DeleteDuplicatesN[x_, n_] :=
x[[
Sort[
Flatten[#[[1 ;; Min[Length[#], n]]]& /@
(Flatten[Position[x, #]]& /@ DeleteDuplicates[x])]]]]
DeleteDuplicatesN[{1, 2, 3, 2, 1, 1, 1, 2, 3, 5, 5, 5, 5, 1, 7, 4, 7, 1}, 3]
{1, 2, 3, 2, 1, 1, 2, 3, 5, 5, 5, 7, 4, 7}
¿Existe un método mejor, más rápido o más elegante?
Por ejemplo, usando solo DeleteDuplicates
o DeleteDuplicatesBy
?
Respuestas
Creo que encontrarás esto más rápido:
dd[list_, n_] :=
Module[{pi = Flatten[Values[PositionIndex[list][[All, ;; UpTo@n]]]]},
list[[Sort@pi]]];
Utilizándolo RandomInteger[20000, 20000]
como una lista de prueba y permitiendo 3 duplicados, su código tomó ~ 37 segundos, esto necesitó ~ 0.03 segundos.
Comparable en velocidad, más simple:
dd2[list_, n_] :=
list[[Union @@
GatherBy[Range@Length@list, list[[#]] &][[All, ;; UpTo@n]]]];
Para listas grandes que no son elementos muy duplicados, esto ofrece una ventaja de rendimiento (por ejemplo, con la RandomInteger[10000000,20000000]
lista de prueba, más de 6 veces la velocidad de los métodos anteriores):
dd=Module[{o = Ordering@#},
o[[o]] = Join @@ Range[Tally[#[[o]]][[All, 2]]];
Pick[#, UnitStep[#2 - o], 1]]&;