私があなたの質問を理解したかどうか見てみましょう。
Mathematicaでコードを段階的に投稿し、コメント付きの出力で簡単にフォローできるようにします。
この回答は、決定論的で順序付けられた出力(つまり、非シャッフル)を提供します。本当にランダム置換が必要な場合は、この同じアルゴリズムを使用して事前に完全にフィルター処理されたシーケンスを生成し、それをシャッフルして、値を1つずつ消費します。
プログラム
まず、2つの定数を定義します。
n = 10; (* nbr of ids *)
m = 3; (* max weight - 1 *)
出力を段階的に確認できるように、数値は小さくしています。
次に、使用するランダムな{id、weight}テーブルを定義します。IDとして素数を使用します。
weights = Table[{Prime@k, RandomInteger[m] + 1}, {k, n}]
出力:
{{2, 3}, {3, 2}, {5, 3}, {7, 1}, {11, 1},
{13, 3}, {17, 1}, {19,4}, {23, 1}, {29, 2}}
次に、重み値を累積します
accumulator = Accumulate[Table[k[[2]], {k, weights}]]
出力:
{3, 5, 8, 9, 10, 13, 14, 18, 19, 21}
そして、両方のテーブルをマージして、アキュムレータをidテーブルに入れます。
weightsAcc = MapThread[Append, {weights, accumulator}]
出力:
{{2, 3, 3}, {3, 2, 5}, {5, 3, 8}, {7, 1, 9}, {11, 1, 10},
{13, 3, 13}, {17, 1, 14}, {19, 4, 18}, {23, 1, 19}, {29, 2, 21}}
次に、デフォルト値(trueまたはfalse)を使用してフィルターを初期化します。Trueを使用しました:
filter = Table[{k[[1]], True}, {k, weights}]
出力:
{{2, True}, {3, True}, {5, True}, {7, True}, {11, True}, {13, True},
{17, True}, {19, True}, {23, True}, {29, True}}
秘訣は、フィルターをidsベクトルと同期させ続けることです。そのため、次のようにフィルターを更新する関数を定義します。
updateFilter[filter_, newValuePair_] :=Return@
ReplaceAll[filter, {newValuePair[[1]], x_} -> newValuePair];
そして、それを使用して2つの値を変更します。
filter = updateFilter[filter, {2, False}];
filter = updateFilter[filter, {5, False}];
Print@filter
出力:
{{2,False},{3,True},{5,False},{7,True},{11,True},{13,True},
{17,True},{19,True},{23,True},{29,True}}
次に、クエリを定義します。2つのグローバル変数(agrhhhh!)と2つの関数を使用して、同期を取ります。
i = 1; j = 0; (* GLOBAL state variables *)
Adjustij[w_] := ( (* parm w is weightsAcc *)
j++; (* increment accumulator comparator*)
If[j == w[[i, 3]], i++]; (* if current id exhausted, get next*)
If[i == Length@w, i = 1; j = 0]; (* wraparound table when exhausted*)
);
query[w_, filter_] := (* parm w is weightsAcc *)
(
Adjustij[w];
While[Not@filter[[i, 2]], Adjustij[w]]; (* get non filtered ids only *)
Return[w[[i, 1]]];
)
もちろん、whileループは、フィルターFalseを使用してIDをスキップするだけで高速化できますが、この方法の方が意図が明確だと思います。
ここで、クエリを30回実行します。
Table[query[weightsAcc, filter], {30}]
そして取得:
{3, 3, 7, 11, 13, 13, 13, 17, 19, 19, 19, 19, 23, 3, 3, 7, 11, 13, \
13, 13, 17, 19, 19, 19, 19, 23, 3, 3, 7, 11}
これは、適切な重みを持つ(周期的に)リストです。ただし、フィルターがFALSEの値は除きます。
HTH!
編集:コメントに答えるために分割されたサーバーとクライアントのコード
異なるフィルターを使用して同時クエリを処理できます
フィルタの状態はクライアントに保存されます。
サーバー-実装された関数とコード:
Clear["Global`*"];
(*Server Implemented Functions follows*)
AdjustFilterState[fs_] := Module[{i, j}, ( (*fs = filterstate, i,j localvars*)
i = fs[[1]]; (*local vars*) (*w = weights with accs*)
j = fs[[2]];
j++; (* increment accumulator comparator*)
If[j == weightsAcc[[i, 3]], i++]; (* if current id exhausted, get next*)
If[i == Length@weightsAcc, i = 1; j = 0];(* wraparound table when exhausted*)
Return[{i, j}];);
];
query[filter_, fs_] := Module[{fsTemp}, (*fs = filterstate*)
(
fsTemp = AdjustFilterState[fs]; (* local var *)
While[Not@filter[[fsTemp[[1]], 2]], (* get non filtered ids only *)
fsTemp = AdjustFilterState[fsTemp]
];
Return[{weightsAcc[[fsTemp[[1]], 1]], fsTemp}]; (*return[value,{filterState}]*)
)
];
initFilter[] := masterFilter; (*Init filters to your defult vallue*)
(*The trick is to get the filter coordinated with the list value*)
updateFilter[f_, newValuePair_] :=
Return@ReplaceAll[f, {newValuePair[[1]], x_} -> newValuePair];
(*Server Code - Just initialize the whole thing
The SERVER stores ONLY the weights vectors and a master filter initialized*)
n = 10; (* nbr of ids *) (*init vars*)
m = 3; (*max weight - 1 *)
weights = Table[{Prime@k, RandomInteger[m] + 1}, {k, n}]; (*random weights to test*)
accumulator = Accumulate[Table[k[[2]], {k, weights}]];
weightsAcc = MapThread[Append, {weights, accumulator}]; (*add acummulator to list*)
masterFilter= Table[{k[[1]],True}, {k,weights}]; (* only ONE virgin filter in server*)
クライアントコード:
(* Client Code
The CLIENT stores only the filter and the filterState*)
(* Set up filter and filterstate *)
filter = initFilter[];
filter = updateFilter[filter, {2, False}]; (*specify particular values*)
filter = updateFilter[filter, {5, False}];
filterState = {1,0}; (* these replace the previous GLOBAL state variables *)
ValuesList = {}; (*for storing results *)
Do[
q1 = query[filter, filterState]; (* do the query *)
AppendTo[ValuesList, q1[[1]]]; (* first element of return is the value *)
filterState = q1[[2]]; (* second element is updated filter state *)
, {30} (*do 30 times*)
];
Print@ValuesList (* print results vector *)