Как рандомизировать массив записей PHP, придавая больший вес более новым элементам? - PullRequest
0 голосов
/ 13 ноября 2011

У меня есть массив записей из базы данных (хотя база данных не имеет отношения к этому вопросу - в конечном итоге она становится массивом «строк», каждая строка представляет собой массив со строковыми ключами, соответствующими имени поля).Например:

$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 ]

1 голос
/ 13 ноября 2011

Вы можете использовать, например. эта функция сравнения:

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=16 имеет 16x больше шансов, чем элемент id=1, появиться раньше в результирующем списке.

0 голосов
/ 14 ноября 2011

После того, как меня вдохновил ответ @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);
0 голосов
/ 13 ноября 2011
//$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 ()

0 голосов
/ 13 ноября 2011

Как насчет разбить его на части по дате, рандомизировать каждый кусок, а затем собрать их обратно в один список?

...