如何随机化PHP数组记录,为更近期的项目赋予更多权重?

时间:2011-11-13 04:27:45

标签: php random weighted

我有一个来自数据库的记录数组(尽管数据库与这个问题无关 - 它最终变成了一个“行”数组,每一行都是一个数组,字符串键对应于字段名)。例如:

$items = array(
    1 => array('id' => 1, 'name' => 'John', 'created' => '2011-08-14 8:47:39'),
    2 => array('id' => 2, 'name' => 'Mike', 'created' => '2011-08-30 16:00:12'),
    3 => array('id' => 5, 'name' => 'Jane', 'created' => '2011-09-12 2:30:00'),
    4 => array('id' => 7, 'name' => 'Mary', 'created' => '2011-09-14 1:18:40'),
    5 => array('id' => 16, 'name' => 'Steve', 'created' => '2011-09-14 3:10:30'),
    //etc...
);

我想要做的是将这个数组洗牌,但不知何故给予具有更新“创建”时间戳的项目更多“权重”。随机性不一定是完美的,确切的重量对我来说并不重要。换句话说,如果有一些快速而简单的技术对人类来说似乎是随机的,但在数学上并不是随机的,那我也没关系。另外,如果这对于时间戳的“无限连续统一”并不容易,那么将每条记录分配到一天或一周就可以了,只需根据它们在哪一天或哪一周进行加权。

相对快速/高效的技术是首选,因为这种随机化将发生在我网站中某个页面的每个页面加载上(但是如果不能有效地执行,我可以定期运行并缓存结果)

4 个答案:

答案 0 :(得分:1)

你可以使用例如。这个比较函数:

function cmp($a, $b){
    $share_of_a = $a['id'];
    $share_of_b = $b['id'];
    return rand(0, ($share_of_a+$share_of_b)) > $share_of_a ? 1 : -1;
}

然后像这样使用它:

usort($items, 'cmp');

它比较数组的两个元素基于它们的ID (它更容易,它们根据创建日期分配 - 较新的元素具有更大的ID)。比较是随机进行的,每个元素的成功机会不同,为新元素提供了更多机会。 ID越大(元素越新),开始时出现的可能性就越大

例如,id=16元素的 16x 比元素id=1更早出现在结果列表中的机会。

答案 1 :(得分:0)

如何按日期将其拆分为块,随机化每个块,然后将它们作为一个列表重新组合在一起?

答案 2 :(得分:0)

//$array is your array
$mother=array();
foreach($array as $k->$v) $mother[rand(0,count($array))][$k]=$v;
ksort($mother);
$child=array();
foreach($mother as $ak->$av)
foreach($av as $k->$v) $child[$k]=$v;
$array=$child;

或者你可以使用shuffle()

答案 3 :(得分:0)

在受到@Tadeck的回应部分启发之后,我想出了一个解决方案。这有点啰嗦,如果有人可以简化它会很棒。但似乎工作得很好:

//Determine lowest and highest timestamps
$first_item = array_slice($items, 0, 1);
$first_item = $first_item[0];
$min_ts = strtotime($first_item['created']);
$max_ts = strtotime($first_item['created']);
foreach ($items as $item) {
    $ts = strtotime($item['created']);
    if ($ts < $min_ts) {
        $min_ts = $ts;
    }
    if ($ts > $max_ts) {
        $max_ts = $ts;
    }
}

//bring down the min/max to more reasonable numbers
$min_rand = 0;
$max_rand = $max_ts - $min_ts;

//Create an array of weighted random numbers for each item's timestamp
$weighted_randoms = array();
foreach ($items as $key => $item) {
    $random_value = mt_rand($min_rand, $max_rand); //use mt_rand for a higher max value (plain old rand() maxes out at 32,767)
    $ts = strtotime($item['created']);
    $ts = $ts - $min_ts; //bring this down just like we did with $min_rand and $max_rand
    $random_value = $random_value + $ts;
    $weighted_randoms[$key] = $random_value;
}

//Sort by our weighted random value (the array value), with highest first.
arsort($weighted_randoms, SORT_NUMERIC);

$randomized_items = array();
foreach ($weighted_randomsas $item_key => $val) {
    $randomized_items[$item_key] = $items[$item_key];
}

print_r($randomized_items);