Возможный дубликат:
Создание случайных результатов по весу в PHP?
У меня есть веб-приложение, в котором пользователи могут добавлять 1-20 строк текста и присваивать им вес, как часто он должен появляться. Затем система выбирает случайную строку, основанную на определенных весах. Каков наилучший способ сделать это? Значения диапазона для веса каждой строки? Могу ли я просто назначить пользователю номер (0-100) для каждой строки? Как бы вы выбрали случайную строку? (Каждый выбор не беспокоится о том, что было выбрано раньше, каждая строка имеет одинаковые шансы (по весу) выбора в начале каждого вызова).
Я использую эту функцию в нескольких игровых движках PHP:
<?php /** * @param array $values - just the weights * @return integer A number between 0 and count($values) - 1 */ function getBucketFromWeights($values) { $total = $currentTotal = $bucket = 0; $firstRand = mt_rand(1, 100); foreach ($values as $amount) { $total += $amount; } $rand = ($firstRand / 100) * $total; foreach ($values as $amount) { $currentTotal += $amount; if ($rand > $currentTotal) { $bucket++; } else { break; } } return $bucket; }
Применение
Предположим, что у меня есть вес пользователя в ассоциативном массиве, где каждая строка указывает на его вес:
$weighted_strings = array( "important string" => 100, "terrible string" => 10, "never string" => 0, // etc );
Если бы я хотел потянуть строку по весу, я бы сделал это:
$weights = array_values($weighted_strings); $strings = array_keys($weighted_strings); $index = getBucketFromWeights($weights); $selectedString = $strings[$index];
Вот простая реализация:
function Probability($data, $number = 1) { $result = array(); if (is_array($data) === true) { $data = array_map('abs', $data); $number = min(max(1, abs($number)), count($data)); while ($number-- > 0) { $chance = 0; $probability = mt_rand(1, array_sum($data)); foreach ($data as $key => $value) { $chance += $value; if ($chance >= $probability) { $result[] = $key; unset($data[$key]); break; } } } } return $result; }
неfunction Probability($data, $number = 1) { $result = array(); if (is_array($data) === true) { $data = array_map('abs', $data); $number = min(max(1, abs($number)), count($data)); while ($number-- > 0) { $chance = 0; $probability = mt_rand(1, array_sum($data)); foreach ($data as $key => $value) { $chance += $value; if ($chance >= $probability) { $result[] = $key; unset($data[$key]); break; } } } } return $result; }
С помощью этой функции вы можете указать, сколько уникальных взвешенных случайных элементов вы хотите ( IDEOne ).
Хороший ответ предоставляется здесь, но есть способ сохранить цикл loockup. Более быстрый способ выбора случайного значения из массива . На самом деле идея одинакова, просто работает быстрее, как простой цикл.