Update
My original answer worked by flattening the list, finding all positions of each number, deleted one of those positions, then set the remaining positions to Inactive[Nothing]
, repartitioned the list to it's original form, and then activated the list. The speed bottleneck was deleting a representative from each class since it used RandomInteger
as many times as there were sublists.
My update instead uses one RandomReal
call to determine which position to remove from each set of positions, and is about twice as fast:
rru2[list_]:=Module[{flat = Flatten@list, pi, lens, p, keep, remove},
pi = PositionIndex @ flat;
p = Values @ pi;
lens = Length /@ p;
keep = Accumulate[lens] - Floor[RandomReal[1, Length[lens]] lens];
remove = Flatten[p][[Complement[Range @ Length @ flat, keep]]];
flat[[remove]] = Inactive[Nothing];
Activate @ TakeList[flat, Length /@ list]
]
Comparison using @JEM_Mosig's test data:
test3 = DeleteDuplicates /@ Split[RandomInteger[{1,8000},10000], RandomChoice[{0.8,0.2}->{True,False}]&];
rru2[test3]; //RepeatedTiming
rru[test3]; //RepeatedTiming
{0.015, Null}
{0.029, Null}
Original answer
Here is one idea:
rru[list_]:=Module[{flat = Flatten@list, pi},
pi = PositionIndex @ flat;
flat[[Flatten @ Values @ Map[deleteRandom] @ pi]] = Inactive[Nothing];
Activate @ TakeList[flat, Length/@list]
]
deleteRandom[a_] := Delete[a, RandomInteger[{1,Length[a]}]]
Here is a run of 100 applications of rru
:
Tally @ Table[rru[test], {100}] //Column //TeXForm
$\begin{array}{l}
\{\{\{1\},\{7,2,8,5\},\{3\}\},8\} \\
\{\{\{1\},\{2,8,5\},\{7,3\}\},7\} \\
\{\{\{1,5\},\{7,2,8\},\{3\}\},11\} \\
\{\{\{1,3,5\},\{2,8\},\{7\}\},8\} \\
\{\{\{5\},\{2,8\},\{7,1,3\}\},3\} \\
\left\{\left(
\begin{array}{cc}
1 & 5 \\
2 & 8 \\
7 & 3 \\
\end{array}
\right),10\right\} \\
\{\{\{5\},\{7,2,8\},\{1,3\}\},5\} \\
\{\{\{1,3,5\},\{7,2,8\},\{\}\},6\} \\
\{\{\{3\},\{2,8,5\},\{7,1\}\},9\} \\
\{\{\{1,3\},\{7,2,8,5\},\{\}\},5\} \\
\{\{\{\},\{2,8,5\},\{7,1,3\}\},6\} \\
\{\{\{3\},\{7,2,8,5\},\{1\}\},5\} \\
\{\{\{3,5\},\{7,2,8\},\{1\}\},5\} \\
\{\{\{1,3\},\{2,8,5\},\{7\}\},6\} \\
\left\{\left(
\begin{array}{cc}
3 & 5 \\
2 & 8 \\
7 & 1 \\
\end{array}
\right),4\right\} \\
\{\{\{\},\{7,2,8,5\},\{1,3\}\},2\} \\
\end{array}$
ReplacePart[test, Flatten[Values[If[Length[#] == 1, Nothing, Complement[#, {RandomChoice[#]}]] & /@ Merge[Flatten[MapIndexed[Rule, test, {2}]], Identity]], 1] -> Nothing]
$\endgroup$