整数のリストを受け取り、リストの要素に基づいてリストのインデックスのパーティションを返す関数を作成したいと思います。
例えば:
{1,3,3,7} --> { {1}, {2,3}, {4}}
{3,1,3} --> {{1,3}, {2}}
これを行う面倒な方法を思いつきますが、Mathematica でこれを行う自然な方法はありますか?
整数のリストを受け取り、リストの要素に基づいてリストのインデックスのパーティションを返す関数を作成したいと思います。
例えば:
{1,3,3,7} --> { {1}, {2,3}, {4}}
{3,1,3} --> {{1,3}, {2}}
これを行う面倒な方法を思いつきますが、Mathematica でこれを行う自然な方法はありますか?
私は使うだろう:
indicies[x_] := Reap[MapIndexed[Sow[#2, #] &, x]][[2, All, All, 1]]
これは、多くの一意の要素を含む長いリストで を繰り返し使用するよりもはるかに高速です。Position
例:
list = RandomInteger[9999, 10000];
Timing[
result1 =
Function[x, (Flatten@Position[x, #] &) /@ DeleteDuplicates[x]]@list;
]
{3.463, Null}
Timing[
result2 = indicies @ list;
]
{0.031, Null}
result1 === result2
True
TomD
とGatherBy
の代わりに新しい方を使用することをお勧めします。これは、繰り返しがほとんどない長いリストではさらに高速です。Sow
Reap
indicies2[x_] := GatherBy[List ~MapIndexed~ x, First][[All, All, 2, 1]]
list2 = RandomInteger[99999, 100000];
Do[indicies @ list2, {10}] // Timing
Do[indicies2 @ list2, {10}] // Timing
{5.523, Null} {2.823, Null}
速度は、繰り返しが多いリストの方が似ています。
list3 = RandomInteger[99, 100000];
Do[indicies @ list3, {10}] // Timing
Do[indicies2 @ list3, {10}] // Timing
{1.716, Null} {1.607, Null}
純粋な速度を追求する場合MapIndexed
は、パックされた配列用に最適化されていないことを認識する必要があります。したがってRange
、Transpose
その場合はかなり高速になります。
indicies3[x_] := GatherBy[{x, Range@Length@x}\[Transpose], First][[All, All, 2]]
Do[indicies3 @ list2, {10}] // Timing
{1.981, Null}
Do[indicies3@list3, {10}] // Timing (* big difference here *)
{0.125, Null}
1 つの可能性:
Function[x, (Flatten@Position[x, #] &) /@ DeleteDuplicates[x]]@{1, 3,
3, 7}
与える
(* {{1}, {2, 3}, {4} *)
もう一つの例:
lst = {1, 3, 3, 3, 7, 4, 3};
Function[x, (Flatten@Position[x, #] &) /@ DeleteDuplicates[x]]@lst
与える:
(*{{1}, {2, 3, 4, 7}, {5}, {6}}*)
さらに別のアプローチ:
f[x_] := Flatten[x~Position~First@#] & /@ Gather@x