This is almost a duplicate of Ordering function with recognition of duplicates. It is related to Efficiently finding the positions of a large list of targets in another, even larger list but since you apparently want all unique elements I believe it is closer to the first.
Using myOrdering
from the first referenced question:
myOrdering[a_List] := GatherBy[Ordering @ a, a[[#]] &]
fn[a_List] := {Union @ a, myOrdering @ a}\[Transpose]
fn @ mylist
{{1, {8}}, {2, {2, 4, 6}}, {4, {1}}, {5, {5}}, {7, {3, 7}}}
Version 10 update
The new-in-v10 GroupBy
can combine the two lines of code in my original answer:
fn2[a_] := GroupBy[Ordering @ a, a[[#]] &]
<|1 -> {8}, 2 -> {2, 4, 6}, 4 -> {1}, 5 -> {5}, 7 -> {3, 7}|>
The result is an Association
which has value in itself. However fn2
is not as fast as my original fn
.
Timings
Responding to Mike Honeychurch's implicit request for timings, here is my function (in its current version) versus both ubpdqn and his Sow
/Reap
method, performed in version 10.0.1.
mylist = RandomInteger[2*^5, 5*^5];
fn @ mylist // Timing // First
fn2 @ mylist // Timing // First
Last@Reap[MapThread[Sow, {Range[Length[mylist]], mylist}], _, List] // Timing // First
Last@Reap[MapIndexed[Sow[First[#2], #1] &, mylist], _, List] // Timing // First
0.265202
0.702005
3.619223
4.118426
Note that both Sow
/Reap
methods are the un-sorted variation; adding a sort would incur an additional overhead.