PHPのSTR_SHUFFLE関数は、多くの場合、文字列のシーケンスをランダムに破壊し、さまざまなランダムな順列を生成するために使用されます。次のような使用は非常に簡単です。
<?php
$original = "abcdef";
$shuffled = str_shuffle($original);
echo $shuffled;
?>
このコードが実行されるたびに、元の文字列のランダムな順列の組み合わせを返します。ただし、いくつかのアプリケーションシナリオでは、検証コードの生成、ランダムパスワード、宝くじシーケンスなど、生成されたランダムな組み合わせを繰り返さないようにします。
ただし、 STR_SHUFFLEのランダムな性質により、特にサンプルサイズが小さくなったり、呼び出し数が大きい場合に、呼び出すたびに同じ順列を生成することも可能です。重複の確率は大幅に増加します。それでは、重複した文字の組み合わせの生成を避ける方法は?ここにいくつかの実用的な戦略があります。
最も直感的な方法は、新しいランダム文字列を生成し、配列またはコレクションに保存することです。新しい文字列を生成するときは、既に存在するかどうかを確認し、存在する場合は再生します。
<?php
$original = "abcdef";
$generated = [];
function generateUniqueShuffle($str, &$history) {
do {
$shuffled = str_shuffle($str);
} while (in_array($shuffled, $history));
$history[] = $shuffled;
return $shuffled;
}
// 例:生成する10ユニークなランダムな組み合わせ
for ($i = 0; $i < 10; $i++) {
echo generateUniqueShuffle($original, $generated) . "\n";
}
?>
この方法は単純ですが、世代の数が増えると、重複チェックが遅くなり、最終的には目的の数よりも少ない(制限された組み合わせ)が生成される可能性があります。
文字列のすべての順列は限られています(長さnの文字列にはn!順列があります)。最初に再帰アルゴリズムを使用して、すべての順列を生成し、保存してから、ランダムに抽出してそれらから補償することができます。
例は、完全に配置されたコアコードを生成します。
<?php
function permute($str, $prefix = '') {
$result = [];
$len = strlen($str);
if ($len == 0) {
$result[] = $prefix;
} else {
for ($i = 0; $i < $len; $i++) {
$rem = substr($str, 0, $i) . substr($str, $i + 1);
$result = array_merge($result, permute($rem, $prefix . $str[$i]));
}
}
return $result;
}
$original = "abc";
$allPermutations = permute($original);
shuffle($allPermutations); // ランダム破壊順序
foreach ($allPermutations as $perm) {
echo $perm . "\n";
}
?>
この方法は、列の長さ(通常は8未満)に適しています。これは、多くのメモリと時間を消費する完全な順列の数(8!= 40320)が爆発するためです。
リクエスト間の重複を避ける必要がある場合、または長い間、データベースまたはキャッシュ(Redisなど)に生成された組み合わせを記録し、各世代の後に複製されているかどうかを確認してから、返すかどうかを決定できます。
この方法は、マルチユーザー環境で非常に実用的であるか、ランダムな組み合わせの大きなバッチを生成し、過度のメモリ使用量を回避し、一意性を確保するときです。
例の擬似コードのアイデア:
<?php
// データベースに接続します,現在の組み合わせが既に存在するかどうかをクエリします
// ある場合,再生する,直到生成する唯一组合
// 新しい組み合わせをデータベースに挿入して保存します
?>
特定の実装は、データベースシステムと使用するビジネスニーズに依存します。
単純な繰り返しを避けている場合は、 str_shuffleとランダムな文字置換を組み合わせてランダムスペースを増やすこともできます。たとえば、破壊後、他の許可された文字セットのいくつかの文字をランダムに置き換えます。
これにより、繰り返しの可能性が低下しますが、絶対にユニークであることは保証されていません。
小規模で簡単なシナリオ:生成された結果を配列で保存し、ループ検出は重複を回避します。
中サイズと短い弦:ランダムに描画された事前に生成された完全な順列。
大規模で永続的な一意性:データベースまたはキャッシュを使用して、レコードを推定します。
強化されたランダム性:他のランダム変換方法と組み合わせて、繰り返しの可能性を減らします。
戦略を選択するときは、文字列の長さ、世代数、パフォーマンス、およびメモリの使用量を比較検討し、合理的なソリューションを設計する必要があります。