Mathematicaで重複を表示
-
06-07-2019 - |
質問
Mathematicaにはリストがあります:
x = {1,2,3,3,4,5,5,6}
重複を含むリストを作成するにはどうすればよいですか?いいね:
{3,5}
リストとしてのリストを探しています。リストの[]を除いて、次のことができます。
unique = Union[x]
duplicates = MyExcept[x,unique]
(もちろん、xに3つ以上の重複がある場合、たとえば{1、 2,2,2 、3,4,4}の場合、出力は{2、 2,4}、ただし追加のUnion []はこれを解決します。)
しかし、そのようなものはありませんでした(そこにあるすべての機能をよく理解していれば)。
では、その方法はどうですか?
解決
このようなリスト抽出を行う多くの方法。私が最初に思いついたのは次のとおりです。
Part[Select[Tally@x, Part[#, 2] > 1 &], All, 1]
または、より読みやすく分割して:
Tally@x Select[%, Part[#, 2] > 1 &] Part[%, All, 1]
それぞれを与える
{{1, 1}, {2, 1}, {3, 2}, {4, 1}, {5, 2}, {6, 1}} {{3, 2}, {5, 2}} {3, 5}
おそらく、より効率的な(時間またはコード空間で)方法を考えることができます:)
ところで、リストがソートされていない場合は、これが機能する前にまずリストで Sort
を実行する必要があります。
他のヒント
これは、リストを1回パスするだけで実行できます。
collectDups[l_] := Block[{i}, i[n_]:= (i[n] = n; Unevaluated@Sequence[]); i /@ l]
例:
collectDups[{1, 1, 6, 1, 3, 4, 4, 5, 4, 4, 2, 2}] --> {1, 1, 4, 4, 4, 2}
一意の重複リスト- {1、4、2}
が必要な場合は、上記を DeleteDuplicates
でラップします。これは、リスト( Union
は結果をソートするため効率が低下します)。
collectDups[l_] :=
DeleteDuplicates@Block[{i}, i[n_]:= (i[n] = n; Unevaluated@Sequence[]); i /@ l]
ウィル・ロバートソンのソリューションは、それがより簡単だからという理由だけでおそらくより良いでしょうが、もしあなたがもっとスピードを出したいなら、これが勝つと思います。しかし、それを気にかけているのなら、Mathematicaでプログラミングすることはないでしょう! :)
Tallyメソッドのより高速なバリエーションがいくつかあります。
f4
は" tricks"を使用します。 MathGroupでCarl WollとOliver Ruebenkoenigによって与えられました。
f2 = Tally@# /. {{_, 1} :> Sequence[], {a_, _} :> a} &;
f3 = Pick[#, Unitize[#2 - 1], 1] & @@ Transpose@Tally@# &;
f4 = # ~Extract~ SparseArray[Unitize[#2 - 1]]["NonzeroPositions"] & @@ Transpose@Tally@# &;
速度の比較( f1
は参照用に含まれています)
a = RandomInteger[100000, 25000];
f1 = Part[Select[Tally@#, Part[#, 2] > 1 &], All, 1] &;
First@Timing@Do[#@a, {50}] & /@ {f1, f2, f3, f4, Tally}
SameQ @@ (#@a &) /@ {f1, f2, f3, f4}
Out[]= {3.188, 1.296, 0.719, 0.375, 0.36}
Out[]= True
f4
が純粋な Tally
に比べてオーバーヘッドがほとんどないことは驚くべきことです!
dreevesのようなソリューションを使用しますが、複製された各要素の単一のインスタンスのみを返すことは、ちょっと面倒です。その方法の1つは次のとおりです。
collectDups1[l_] :=
Module[{i, j},
i[n_] := (i[n] := j[n]; Unevaluated@Sequence[]);
j[n_] := (j[n] = Unevaluated@Sequence[]; n);
i /@ l];
これは、要素が重複していると判断できる順序で返されるリストに表示されるため、ウィルロバートソン(IMO上位)ソリューションによって生成される出力と正確には一致しません。単一のパスで実際に実行できるかどうかはわかりませんが、考えられるすべての方法には、実際には少なくとも2つのパスが含まれますが、1つは複製された要素のみである場合があります。
これは、100%の「後置記法」を使用したRobertsonの回答のバージョンです。関数呼び出し用。
identifyDuplicates[list_List, test_:SameQ] :=
list //
Tally[#, test] & //
Select[#, #[[2]] > 1 &] & //
Map[#[[1]] &, #] &
Mathematicaの //
は、他の言語のメソッド呼び出しのドットに似ています。たとえば、これがC#/ LINQスタイルで記述されている場合、次のようになります
list.Tally(test).Where(x => x[2] > 1).Select(x => x[1])
C#の Where
はMMAの Select
に似ており、C#の Select
はMMAの Map
に似ています。
EDIT:オプションのテスト関数引数を追加しました。デフォルトは SameQ
です。
編集:これは、以下のコメントに対応するバージョンです&値が等しい場合、リストの要素が同等であると見なされるような値を生成するプロジェクター関数を与えられたグループ内のすべての同等物を報告します。これは本質的に、指定されたサイズより長い等価クラスを見つけます:
reportDuplicateClusters[list_List, projector_: (# &),
minimumClusterSize_: 2] :=
GatherBy[list, projector] //
Select[#, Length@# >= minimumClusterSize &] &
最初の要素の整数のペアをチェックするサンプルです。最初の要素が等しい場合、同等の2つのペアを考慮します
reportDuplicateClusters[RandomInteger[10, {10, 2}], #[[1]] &]
このスレッドは古いようですが、自分で解決しなければなりませんでした。
これは一種の粗野ですが、これはそれを行いますか?
Union[Select[Table[If[tt[[n]] == tt[[n + 1]], tt[[n]], ""], {n, Length[tt] - 1}], IntegerQ]]
リストAを指定すると、
B
で重複しない値を取得する
B = DeleteDuplicates [A]
Cで重複した値を取得する
C =補数[A、B]
D
の重複リストから重複しない値を取得する
D = DeleteDuplicates [C]
つまり、あなたの例では:
A = 1、2、2、2、3、4、4
B = 1、2、3、4
C = 2、2、4
D = 2、4
したがって、答えはDeleteDuplicates [Complement [x、DeleteDuplicates [x]]]になります。xはリストです。私は数学を知らないので、構文はここで完璧かもしれないし、そうでないかもしれません。リンクしたページのドキュメントをご覧ください。