【问题标题】:Shuffles Random Numbers with no repetition in Javascript/PHP在 Javascript/PHP 中无重复随机数
【发布时间】:2013-02-06 20:51:55
【问题描述】:

我在这里搜索了一些答案,但它似乎不是我需要的东西,或者我只是不知道如何应用它。

我还没有开始任何代码,我只是在想如何去做,我不知道如何去做。我需要你们的帮助。

假设我有一个由以下这些值组成的数组

[1,2,3,4,5,6,7,8,9]

我需要随机播放它而不重复最后一个结果的每个数字的位置。所以它可能会喜欢

[5,3,9,6,2,8,1,4,7]

如果我再次随机播放它会是这样的

[4,7,2,1,8,3,6,9,5]

等等。

好吧,我不知道是否有任何相关性,但我宁愿不使用 rand()。这东西有什么解决办法吗?

【问题讨论】:

  • 您想创建所有可能的组合吗?如果不只是打乱数组,请将其与每个已经打乱的数组进行比较。如果匹配则重新洗牌,如果不匹配则添加。
  • 在php中你可以使用函数shuffle(&$array)。传递一个数组 - 它会为你洗牌。您不能保证持续不重复,但您在随后的两次调用中获得重复结果的可能性非常非常小。
  • 您还可以将数组拆分为较小的数组,将它们打乱,然后以随机顺序从较小的数组重新创建大数组。所以你最终得到 [2,3,1][6,5,4][8,9,7] 然后可能是 [6,5,4][2,3,1][8,9,7]合并后变为:[6,5,4,2,3,1,8,9,7]
  • 所以您不希望数字在同一位置重复多少次迭代/混洗?
  • @Bergi 据我了解,他不会每个数字重复相同/最后一个位置,因为它是 n suffles。所以它不是重复的

标签: php javascript arrays shuffle


【解决方案1】:

试试这个,

$count = 15;
$values = range(1, $count);
shuffle($values);
$values = array_slice($values, 0, 15);

$numbers = array();
do {
   $possible = rand(1,15);
   if (!isset($numbers[$possible])) {
      $numbers[$possible] = true;
   }
} while (count($numbers) < 15);
print_r(array_keys($numbers));

希望对您有所帮助。

【讨论】:

    【解决方案2】:

    您要做的是将数组中的元素随机添加到另一个数组中,但要确保元素不在相同的索引位置。试试这个:

    $array = [1,2,3,4,5,6,7,8,9];
    $new = array();
    for($i = 0; $i < $array.length; $i++){
      $rand = $i;
      do {
        $rand = Math.floor( Math.random() * ( $array.length + 1 ) );
      } while ($rand == $i || array_key_exists($rand, $new))
      // Check that new position is not equal to current index
      // and that it doesnt contain another element
    
      $new[$rand] = $array[i];
    }
    

    不是最有效的,但保证将元素放在不同的索引中。

    【讨论】:

    • 其实效率很低,还有更优雅的解决方案可以保证i != j
    【解决方案3】:

    您可以使用Fisher-Yates-Shuffle 的变体,它会随机选择交换的元素,称为Sattolo's algorithm

    function shuffleArray(array) {
        for (var i = array.length - 1; i > 0; i--) {
            var j = Math.floor(Math.random() * i); // no +1 here!
            var temp = array[i];
            array[i] = array[j];
            array[j] = temp;
        }
        return array;
    }
    

    这样,每个元素都可以保证被交换,并且不会出现在与以前相同的位置。

    【讨论】:

    • @joe:不太可能(或者更确切地说,考虑到算法,不可能,只要数组有超过 1 个元素)。您可以演示一下您的代码(例如小提琴)吗?
    • @joe:您可能已经got a problem with your console output,因为您反复记录同一个数组。试试this oneshuffleArray没有改)
    • 它给出了相同的结果。第二个日志实际上是相同的 [1,2,3],所以位置是重复的。
    • @joe 当然第二个可以和原来的输入一样,只是保证在所有位置都和第一个不同。
    • duh :D 我刚刚意识到问题所在。它返回相同的数组(修改原始数组),因此下一个调用将开始改组类似 [3,1,2] 的东西,它可以返回 [1,2,3],因为它们不在相同的位置:)
    【解决方案4】:

    这使得数组的值不会重复 n 次随机播放的任何先前位置(我使用数组大小​​的一半作为 n,之后我重新启动禁止索引)。最后修改了这个版本,使它不重复当前位置。

    为此,您必须保存原始数组的每个值所在的所有索引的历史记录。为此,我为您的数字增加了一点复杂性

    var numberArray = [{value:1, unavailable_indexes:[0]},
                       {value:2, unavailable_indexes:[1]},
                       {value:3, unavailable_indexes:[2]},
                       {value:4, unavailable_indexes:[3]},
                       {value:5, unavailable_indexes:[4]},
                       {value:6, unavailable_indexes:[5]},
                       {value:7, unavailable_indexes:[6]},
                       {value:8, unavailable_indexes:[7]},
                       {value:9, unavailable_indexes:[8]}
                      ];
    

    这样你就有了值中的数字和它所在的所有位置的数组。接下来我们需要运行所有数组并切换数字。

    var arrayLen = numberArray.length-1;
    $.each(numberArray, function(index, value){
        var newIndex;
        //restart the array when half of the index have been covered or it will take awhile to get a random index that wasn't used
        if(value.unavailable_indexes.length >= numberArray.length/2)
            value.unavailable_indexes = [index];//restart the unavailable indexes with the current index as unavailable
        do{
            newIndex = Math.floor(Math.random()*arrayLen);
        //verify if you can swap the 2 values, if any of them have been on the destination index get another random index
        }while($.inArray(value.unavailable_indexes, newIndex) || $.inArray(numberArray[newIndex].unavailable_indexes, index));
    
    
        numberArray[index] = numberArray[newIndex];
        numberArray[newIndex] = value;
    })
    

    在所有阵列移动后,您需要保存它们降落的位置

    $.each(numberArray, function(index, value){
       value.unavailable_indexes.push(index);
    }
    

    编辑:如果你只是想防止它重复之前的位置,那么让 unavailable_indexes 保持它所在的最后一个位置并将do{...}while() 替换为:

    do{
        newIndex = Math.floor(Math.random()*arrayLen);
    }while(newIndex != value.unavailable_indexes)
    

    最后一个方法看起来像:

    $.each(numberArray, function(index, value){
       value.unavailable_indexes = index;
    }
    

    【讨论】:

      【解决方案5】:

      我刚刚想出了以下代码,以解决我遇到的一个问题,有时我的随机打乱的数组会以原始顺序结束(是 随机,还是不随机 够了?)。

      它是如何工作的,它在一个 while 循环中循环,直到 $isDifferent 变量变为 true,这只有在数组不匹配时才会发生。这可能与 Fisher-Yates 方法的工作方式类似,尽管当我尝试这样做时,有时我仍然会得到匹配的数组。

      这个解决方案是用 PHP 编写的,但可以很容易地转换为 JavaScript。

      guaranteedShuffle($array){
          $isDifferent = false;
          while(!$isDifferent){
              $arrayCopy = $array;
              shuffle($arrayCopy);
              if($array !== $arrayCopy){
                  $isDifferent = true;
              }
          }
          return $arrayCopy;
      } 
      

      用法:

      $array = ['1','2']; 
      $shuffled = guaranteedShuffle($array);
      

      【讨论】:

        【解决方案6】:

        您可以使用Fisher Yates Shuffle 随机播放

        function fisherYates ( myArray ) {
        var i = myArray.length, j, tempi, tempj;
        if ( i == 0 ) return false;
        while ( --i ) {
         j = Math.floor( Math.random() * ( i + 1 ) );
         tempi = myArray[i];
         tempj = myArray[j];
         myArray[i] = tempj;
         myArray[j] = tempi;
        }
        }
        

        See this reference

        【讨论】:

        • 没有。这可能会出现最后的结果。
        猜你喜欢
        • 1970-01-01
        • 2013-07-05
        • 2020-10-18
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-04-01
        • 1970-01-01
        相关资源
        最近更新 更多