2

次のような名前の配列があります。

$ donalds_nephews = array('Huey'、'Dewey'、'Louie');

array
(
    [0] => Huey
    [1] => Dewey
    [2] => Louie
)

この配列をシャッフルしたいのですが、元の配列の値がシャッフルされた配列と同じキーを持たないようにしてください。

$donalds_nephews_shuffled = shuffle($donalds_nephews);

これにより、6つの可能な順列が生じる可能性があります。

  1. ヒューイ、デューイ、ルイ
  2. ヒューイ、ルイ、デューイ
  3. デューイ、ルイ、ヒューイ
  4. デューイ、ヒューイ、ルーイ
  5. ルイ、デューイ、ヒューイ
  6. ルイ、ヒューイ、デューイ

1番目、2番目、4番目、5番目は結果であってはなりません。

そうするための最良の方法は何ですか?シークレットサンタ用です。

4

5 に答える 5

5

元の配列をシャッフルしてから、そのコピーを作成し、すべてのエントリを1つ上にシフトしてから、2つを一致させて一致させます。

于 2012-12-12T22:28:37.290 に答える
1

私の秘密のサンタのためにこれが必要だからです:)

<?php

    function compareArrays($original, $shuffled){   
        for($i = 0; $i < count($original); $i++ ){
            if($original[$i] == $shuffled[$i]){
                return false;
            }
        }
        return true;
    }

    $donalds_nephews = array('Huey', 'Dewey', 'Louie','Igor','Stephan');

    //avoid loops
    for($j = 0; $j < 50; $j++){
        $shuffled = $donalds_nephews;
        shuffle($shuffled);
        $good = compareArrays($donalds_nephews, $shuffled);

        if($good) break;
    }

    if($good){
        echo "here we go!\n";
        foreach($shuffled as $k => $v){
            echo "$k => $v \n";
        }
    }
    else { 
        echo "try again \n";
    }

?>
于 2012-12-12T22:53:00.457 に答える
1

シークレットサンタ用です。

次に、より良いアルゴリズムから始めます。現在、キーは現在の提供者であり、値は現在の受信者であると推測しているようです(またはその逆)。次に、追加のチェック(およびシャッフルの繰り返しの可能性)が必要になり、誰も自分にプレゼントを渡さないようにします。

しかし、それを名前の順序付きリストと見なして、各エントリがリストの次の人に与えるとしたらどうでしょうか。

$victims=array('Huey', 'Dewey', 'Louie');
shuffle($victims);
$giver='';
foreach($victims as $receiver) {
  if ($giver) print "$giver gives to $receiver\n";
  $giver=$receiver;
}
$receiver=array_shift($victims);
print "$giver gives to $receiver\n";
于 2012-12-12T22:41:00.797 に答える
0

これらすべてを1つの関数にまとめようとして、これを複雑にしないでください。

これがあなたの擬似コードです:

$givers  = array( 'Huey', 'Dewey', 'Louie' );
$getters = $givers;

foreach ( $givers as $giver ) {
    do {
        pick a random $getter from $getters;
    } until $getter <> $giver;
    delete $getter from $getters;
    print "$giver gives to $getter\n";
}
于 2012-12-12T22:33:23.307 に答える
0

古い質問ですが、あなたは最善の方法を求めたので、これはどうですか?

function santaYates($array) {
    $returnArray = array_values($array); // Cause we need a clean numeric array
    $secure = false;
    for($i = count($returnArray) - 1; $i > 0; $i--) {
        $r = mt_rand(0, $i-1); //subtract 1 from $i to force a new place.
        $tmp = $returnArray[$i];
        $returnArray[$i] = $returnArray[$r];
        $returnArray[$r] = $tmp;
    }

    return $returnArray;
}

フィッシャー-イェーツシャッフルと非常によく似ています。

わずかな違いが1つだけあります。同じキーの使用を許可しているため、すべてのエントリが新しい場所になります(ランダム化ステップを実行するときに$ iから1を引くため)。

作業デモ

于 2019-12-01T22:51:54.980 に答える