【问题标题】:Weighted Shuffle of an Array or Arrays?一个或多个数组的加权洗牌?
【发布时间】:2012-03-13 06:29:17
【问题描述】:

什么是使用嵌套数组的权重对一个或多个数组进行混洗的好算法?

例子:

$array = array(
  array("name"=>"John", "rank"=>3),
  array("name"=>"Bob", "rank"=>1),
  array("name"=>"Todd", "rank"=>8),
  array("name"=>"Todd", "rank"=>14),
  array("name"=>"Todd", "rank"=>4)
);

我希望数组随机打乱,但我希望 rank 值是一个权重。因此,排名较低的人更有可能位于列表的顶部。

我已经尝试了一些事情,例如遍历数组并提取使用 mt_rand(mt_rand(0,$value),$value) 选择的数组,但我认为我的方向不正确...

【问题讨论】:

    标签: php arrays random weighted


    【解决方案1】:

    由于这个问题首先在谷歌上搜索 php array weighted shuffle 并且接受的答案没有解决它 - 这是基于我找到的一些算法的解决方案。

    相当快(对于 PHP),概率分布也经过测试并正确

    <?php
    
    /**
     * Input can be specified as basic array or array of arrays:
     * - array = [key1 => weight1, key2 => weight2, ...]
     * - array = [[..., weightKey => weight], [..., weightKey2 => weight2], ...]
     *
     * Usage:
     *
     * $arr = ['key1' => 1, 'key2' => 2, 'key3' => 3];
     * weighted_shuffle($arr);
     *
     * On average key3 is gonna be the first 50% of the time
     *
     * @param array         $array Array to shuffle
     * @param string|null   $weight_key Optional weight key if input is array of arrays 
     */
    function weighted_shuffle(array &$array, $weight_key = null)
    {
        if($weight_key === null) {
            $arr = $array;
        } else {
            $arr = array_combine(array_keys($array), array_column($array, $weight_key));
        }
        $max = 1.0 / getrandmax();
        array_walk($arr, function (&$v, $k) use($max) {
            $v = pow(rand()*$max, 1.0/$v);
        });
        arsort($arr);
        array_walk($arr, function (&$v, $k) use($array) {
           $v = $array[$k];
        });
        $array = $arr;
    }
    

    【讨论】:

    • 这是这个问题的唯一正确答案,应该被接受为答案。
    【解决方案2】:

    我能够像这样解决这个问题:

    function compare($a, $b)
    {
      $share_of_a = $a['rank'];
      $share_of_b = $b['rank'];
      return mt_rand(0, ($share_of_a+$share_of_b)) > $share_of_a ? 1 : -1;
    }
    
    usort($array, "compare"); // Sort the array using the above compare function when comparing
    $array = array_reverse($array);
    

    【讨论】:

    • 如果您解决了自己的问题,您应该接受自己的答案。
    • 在您发布问题 48 小时后才能接受您自己的答案。
    【解决方案3】:

    你可以试试这样的:

    function weightedshuffle ($a, $b) {
        return rand(0, $a['rank'] + $b['rank']) <= $a['rank'];
    }
    
    usort($data, 'weightedshuffle');
    

    【讨论】:

    • 我不知道 php 的细节,但你肯定不能使用那个函数进行排序——这不是等价关系。
    • 有趣。好吧,我不太确定对不是等价关系的事物进行排序意味着什么,但如果它有效,我想它会有效。
    • 同上,是的 - 你是对的,这是对排序功能的滥用。
    • @AlexanderCorwin usort 使用某种快速排序算法和传递函数作为比较函数。
    猜你喜欢
    • 2021-06-14
    • 1970-01-01
    • 1970-01-01
    • 2015-12-11
    • 1970-01-01
    • 2011-06-11
    • 2013-08-30
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多