Как сделать контролируемый «случайный» заказ? - PullRequest
5 голосов
/ 23 июля 2010

У меня есть набор вопросов игры викторины в базе данных SQL (на самом деле Javascript и SQLite).Все вопросы имеют уровень сложности от 1 до 5, 5 - самый сложный.Вот упрощенная визуализация данных ...


+---------+--------------+  
|   id    | difficulty   |   
+---------+--------------+  
| 1       |      1       |    
| 2       |      5       |    
| 3       |      2       |    
| 4       |      3       |    
| 5       |      2       | 
| 6       |      2       |    
| 7       |      4       |    
| 8       |      1       |    
| 9       |      5       |    
| 10      |      3       |      
+---------+--------------+   

Теперь я могу перетасовать эти штрафы в sql или коде, чтобы они были в случайном порядке без повторов, но я также хочу иметь контроль над способомполе сложности упорядочено.

Так, например, у меня может быть перемешанный набор вопросов, где порядок уровней сложности выглядит следующим образом ...

1,1,5,2,3,3,2,2,2,4

Это несколько «трудностей», это не то, что я хочу.Пользователь, играющий в игру, получит несколько групп одинаково сложных вопросов.Такой порядок был бы лучше ...

1,2,3,2,5,4,1,2,3,2

Я хочу убедиться, что вопросы перемешаны, нобез труда сгущаться.Равномерное распределение трудностей там, где их мало, если есть «комки».Любая помощь по MySQL / javascript (или PHP) будет отличной.

Ответы [ 5 ]

5 голосов
/ 23 июля 2010

Вместо того, чтобы группировать все идентификаторы вместе, почему бы вам не сгруппировать их по сложности, рандомизировать каждый раздел, а затем вытащить их один за другим.Или, как только они отсортированы случайным образом, вы можете вытащить их со случайной сложности, а затем убрать этот уровень сложности, пока у вас не возникнет вопрос от каждого.

Это то, о чем я думал в ответ на sje397, поэтому я будудобавьте его к моему ответу.

Пока все остальные варианты суммируются с самой большой группой, кроме одной, у вас не будет комков (если ваш алгоритм верен).Однако алгоритм в основном принимает форму выбора из A (группы с наибольшим количеством вариантов выбора), выбора из другой группы, выбора из A и т. Д., Пока A не станет равным размеру других групп.Таким образом, лучший алгоритм будет проверять, чтобы найти наибольшую группу и выбрать из нее.Затем он выберет другую группу, затем проверит, какая группа является наибольшей, затем выберите из нее, если она не была выбрана ранее и т. Д.

2 голосов
/ 23 июля 2010

Как насчет следующей стратегии в коде: (ниже был маркированный список, но я не мог получить код, появляющийся после маркированного списка для правильного отображения - я полностью ненавижу этот мусор "уценки", используемый этим сайтом)

упорядочить вопросы по сложности

разделить вопросы наполовину на два списка: «простой» список и «жесткий» список

отвечайте на вопросы один за другим из простых и сложных списков, чередуя их. (Это будет означать, что у вас будет небольшая тенденция от простого к сложному в последовательности вопросов, с которыми вы можете или не можете согласиться.)

Примитивная реализация:

$resultset = your_preferred_query_function('SELECT id FROM question ORDER BY difficulty');
$questions_temp = array();
while ( $row = mysqli_fetch_assoc() ) {
    $questions_temp[] = $row['id'];
}
if ( count($questions) % 2 ) {
    $loop_limit = (count($questions) - 1) / 2;
    $halfway = (count($questions) + 1) / 2;
    $questions[0] = $questions_temp[$loop_limit];
} else {
    $loop_limit = count($questions) / 2;
    $halfway = count($questions) / 2;
    $questions = array();
}
for ($i=0; $i<$loop_limit; $i++) {
    $questions[] = $questions_temp[$i];
    $questions[] = $questions_temp[$halfway+$i];
}

Теперь $questions - это массив, содержащий вопросы, упорядоченные, как я предложил.

1 голос
/ 23 июля 2010

Перебирайте произвольно перемешанный входной массив и всякий раз, когда вы ударяете элемент с тем же уровнем сложности, что и предыдущий, меняйте местами следующий элемент, который не имеет такого же уровня сложности. Просто в моей голове, я думаю, что это превратит ваш первоначальный вклад в: 1,5,1,2,3,2,3,2,4,2

В зависимости от ввода, этот подход может привести к слипанию в конце, но может быть достаточно хорошим ...

Если ваш ввод больше, чем вам нужно, вы также можете просто удалить любой элемент, который имеет ту же сложность, что и предыдущий.

1 голос
/ 23 июля 2010

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

0 голосов
/ 23 июля 2010

Очень простое решение (хотя и не очень эффективное):

<?php

        define('MAX_QUESTIONS',10);

        $dbh = new PDO("mysql:dbname=so;host=127.0.0.1","","");
        $sql = "SELECT * FROM q group by difficulty order by rand()";
        $data = $dbh->query($sql);
        $rows = $data->fetchAll();
        $ids = getIds($rows);
        while (count($rows) < MAX_QUESTIONS ) {
                $sql = "SELECT * FROM q where id not in ".
                       "(".join(",",$ids).") group by difficulty order by rand()";
                $data = $dbh->query($sql);
                $more_rows = $data->fetchAll();
                $rows = array_merge($rows,$more_rows);
                $ids = getIds($rows);
        }
        print_r($rows);

        function getIds($data) {
                $ids = array();
                foreach ($data as $v) {
                        $ids[] = $v['id'];
                }
                return $ids;
        }

?>

Это необходимо, потому что группа MySQL всегда возвращает одинаковые идентификаторы, независимо от того, заказывали ли вы ранее (даже в подзапросе.)

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

Плохо то, что вам нужно больше, чем один запрос, и что упорядочение с помощью rand () ужасно неэффективно, но если ваша таблица маленькая, это, вероятно, не будет иметь значения.

...