2011-01-18 21 views
6

Powiel możliwe:
Generating random results by weight in PHP?Picking element losowy przez zdefiniowane przez użytkownika ciężarami

Mam aplikację internetową, na której użytkownicy mogą dodawać 1-20 ciągi tekstowe i przypisać do nich o wadze jak często powinno się pojawiać. System wybiera losowy ciąg na podstawie zdefiniowanych wag. Jaki jest najlepszy sposób na zrobienie tego? Czy wartości zakresu dla wagi dla każdej struny mają znaczenie? Czy mogę po prostu przypisać użytkownikowi numer (0-100) dla każdego ciągu? Jak byś wybrał losowy ciąg? (Każdy wybór nie martwi się o to, co zostało wybrane wcześniej, każdy ciąg ma takie same kursy (w oparciu o wagę) wybranego na początku każdego połączenia).

+1

Powiązane: http://stackoverflow.com/questions/4463561/weighed-random-selection-from-array/4463613#4463613 –

+1

To pytanie pojawia się często. Oto dobry z prostą odpowiedzią: http://stackoverflow.com/questions/445235/generating-random-results-by-weight-inpph –

Odpowiedz

6

mogę używać tej funkcji w kilku silników PHP gra:

<?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; 
} 

Wykorzystanie

Załóżmy, że mam masę użytkowników w tablicy asocjacyjnej gdzie każdy punkty sznurek do jego wagi:

$weighted_strings = array(
    "important string" => 100, 
    "terrible string" => 10, 
    "never string" => 0, 
    // etc 
); 

Gdybym chciał ciągnąć sznur na podstawie wagi, zrobiłbym to:

$weights = array_values($weighted_strings); 
$strings = array_keys($weighted_strings); 
$index = getBucketFromWeights($weights); 
$selectedString = $strings[$index]; 
+2

To może być dalej zoptymalizowane, jeśli zbudujesz odwrotną tablicę asocjacyjną, w której klucze są sumami wag do tej pory, a wartości są ciągami, więc coś takiego: '0 =>" ważny ciąg ", 100 =>" straszny ciąg ", 110 =>" nigdy nie ciąg "", to umożliwia znajdź wybrany element za pomocą wyszukiwania binarnego. Oczywiście tylko dla kilku elementów nie jest to warte wysiłku. – biziclop

+0

@biziclop Jeśli chcesz zrobić wyszukiwanie binarne, nie ma żadnej korzyści z używania tablicy asocjacyjnej zamiast posortowanej listy. –

+0

Kod działa, ale nie mogę zrozumieć logiki. Czy możesz mi wyjaśnić, jak dokładnie to działa. Mam na myśli na przykład jaki jest cel tej linii: $ rand = ($ firstRand/100) * $ total; –

1

Oto prosta realizacja:

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; 
} 

Dzięki tej funkcji można określić, ilu unikalnych ważone elementy losowe chcesz (IDEOne).

-1

Dobra odpowiedź jest tu podana, ale istnieje sposób na zaoszczędzenie pętli loockup. Szybszy sposób na select random value from array. Właściwie Idea jest taka sama, działa szybciej niż zwykła pętla.

Powiązane problemy