n回発生後の重複の削除

Aug 19 2020

の一般化として、DeleteDuplicatesリストから重複を削除したいのですがn、重複の数の後でのみです。

たとえば、n = 33つの複製が許可されることを意味します。

私は自分の機能を作りました:

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}

より良い方法がありますか?より速くまたはよりエレガントですか?

たとえば、DeleteDuplicatesまたはDeleteDuplicatesBy?のみを使用します。

回答

21 ciao Aug 19 2020 at 22:41

私はあなたがこれをより速く見つけると思います:

dd[list_, n_] := 
  Module[{pi = Flatten[Values[PositionIndex[list][[All, ;; UpTo@n]]]]},
   list[[Sort@pi]]];

RandomInteger[20000, 20000]テストリストとして使用し、3回の複製を許可すると、コードは最大37秒かかり、これには最大0.03秒かかりました。

速度が同等で、シンプル:

dd2[list_, n_] := 
  list[[Union @@ 
     GatherBy[Range@Length@list, list[[#]] &][[All, ;; UpTo@n]]]];

大きく重複した要素ではない大きなリストの場合、これによりパフォーマンスが向上します(たとえば、RandomInteger[10000000,20000000]テストリストを使用すると、上記の方法の6倍以上の速度になります)。

dd=Module[{o = Ordering@#},
 o[[o]] = Join @@ Range[Tally[#[[o]]][[All, 2]]];
 Pick[#, UnitStep[#2 - o], 1]]&;