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. 路易、休伊、杜威

第一、第二、第四和第五不得是结果。

最好的方法是什么?这是给秘密圣诞老人的。

4

5 回答 5

5

对原始数组进行洗牌,然后对其进行复制并将所有条目移动一次,然后将两者重新匹配以获得匹配项。

于 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

不要试图将所有这些都放在一个函数中,从而使事情变得复杂。

这是你的伪代码:

$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;
}

它的工作原理与Fisher-Yates shuffle非常相似。

只有一点点不同:我们允许使用相同的密钥,所以每个条目都会得到一个新的位置(因为我们在执行随机化步骤时从 $i 中减去 1)。

工作演示

于 2019-12-01T22:51:54.980 回答