我想做一個函數,它接受一個整數列表並根據列表的元素返回列表的索引分區。Mathematica - 將一個列表變成一個元素位置的分區
例如:
{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}}
我能想到的凌亂的方式來做到這一點,但有一種自然的方式在數學做到這一點?
我會用:
indicies[x_] := Reap[MapIndexed[Sow[#2, #] &, x]][[2, All, All, 1]]
這將是比重複地使用Position
,在很長的名單,具有許多獨特元素更快多。例如:
list = RandomInteger[9999, 10000];
Timing[
result1 =
Function[x, ([email protected][x, #] &) /@ DeleteDuplicates[x]]@list;
]
{3.463, Null}
Timing[
result2 = indicies @ list;
]
{0.031, Null}
result1 === result2
True
TomD
代替Sow
和Reap
使用較新的GatherBy
建議。在長列表中這一點甚至更快,重複性很低。
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
不優化d用於填充陣列,因此Range
和Transpose
會相當快在這種情況下:
indicies3[x_] := GatherBy[{x, [email protected]@x}\[Transpose], First][[All, All, 2]]
Do[indicies3 @ list2, {10}] // Timing
{1.981, Null}
Do[[email protected], {10}] // Timing (* big difference here *)
{0.125, Null}
一種可能性:
Function[x, ([email protected][x, #] &) /@ DeleteDuplicates[x]]@{1, 3,
3, 7}
給予
(* {{1}, {2, 3}, {4} *)
又如:
lst = {1, 3, 3, 3, 7, 4, 3};
Function[x, ([email protected][x, #] &) /@ DeleteDuplicates[x]]@lst
,並提供:
(*{{1}, {2, 3, 4, 7}, {5}, {6}}*)
另一種方法:
f[x_] := Flatten[[email protected]#] & /@ [email protected]
這兩種方法的執行速度似乎取決於列表的內容。對於長度爲1,000,000的列表,只包含兩個值,「指數」('indices'?)是0.78s比0.71s更慢的一個分數。 –
更加優雅。 'GatherBy [MapIndexed [{#1,#2}&,list],First] [[All,All,2,1]]作爲變體? – tomd
@image_doctor好的,如果「位置」只被稱爲幾次,它將會很快,而且我並不是想要以其他方式暗示。我想我應該說「對於許多獨特的元素」而不是長列表。 –