N tekrardan sonra kopyaları silme

Aug 19 2020

Genellemesi olarak DeleteDuplicates, bir listeden kopyaları silmek istiyorum, ancak yalnızca nbirkaç 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 DeleteDuplicatesveya DeleteDuplicatesBy?

Yanıtlar

21 ciao Aug 19 2020 at 22:41

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]]&;