N tekrardan sonra kopyaları silme
Genellemesi olarak DeleteDuplicates
, bir listeden kopyaları silmek istiyorum, ancak yalnızca n
birkaç kopya olduktan sonra .
Diyelim ki, n = 3
üç kopyaya izin verilir.
Kendi işlevimi yaptım:
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}
Daha iyi bir yöntem var mı - daha hızlı mı yoksa daha zarif mi?
Örneğin, yalnızca DeleteDuplicates
veya DeleteDuplicatesBy
?
Yanıtlar
Sanırım bunu daha hızlı bulacaksın:
dd[list_, n_] :=
Module[{pi = Flatten[Values[PositionIndex[list][[All, ;; UpTo@n]]]]},
list[[Sort@pi]]];
Kullanımı RandomInteger[20000, 20000]
~ kodunuzu aldı 37 saniye bir test listesi olarak ve 3 çiftleri izin bu ~ 0.03 saniye gereklidir.
Hızla karşılaştırılabilir, daha basit:
dd2[list_, n_] :=
list[[Union @@
GatherBy[Range@Length@list, list[[#]] &][[All, ;; UpTo@n]]]];
Büyük ölçüde yinelenen öğeler olmayan büyük listeler için bu, bir performans avantajı sunar (örneğin, RandomInteger[10000000,20000000]
test listesiyle, yukarıdaki yöntemlerin 6 katından fazla hız):
dd=Module[{o = Ordering@#},
o[[o]] = Join @@ Range[Tally[#[[o]]][[All, 2]]];
Pick[#, UnitStep[#2 - o], 1]]&;