вопрос
Приветствую.
Делаю тут для паблика один модуль...
И есть один небольшой ньюанс, который мне хотелось бы элегантно решить.
Как известно, стандартный рейтинг DLE хранит 2 параметра: общая сумма оценок и количество голосов.
Т.е. если рейтинг 4.5 и при этом 12 голосов, то хранимое значение рейтинга будет 54.
Суть вопроса в следующем. Нужно написать скрипт/алгоритм, который должен посчитать сколько было оценок 5 баллов, сколько 4, 3, 2 и 1.
Естественно ни о какой 100% точности не может быть и речи. Ведь например если есть 4 голоса и рейтинг 14, то это вполне может быть:
Так что вот такая интересная задачка :) Если есть желающие - приглашаю присоединиться к мозговому штурму :)
Делаю тут для паблика один модуль...
И есть один небольшой ньюанс, который мне хотелось бы элегантно решить.
Как известно, стандартный рейтинг DLE хранит 2 параметра: общая сумма оценок и количество голосов.
Т.е. если рейтинг 4.5 и при этом 12 голосов, то хранимое значение рейтинга будет 54.
54/12 = 4.5
Суть вопроса в следующем. Нужно написать скрипт/алгоритм, который должен посчитать сколько было оценок 5 баллов, сколько 4, 3, 2 и 1.
Естественно ни о какой 100% точности не может быть и речи. Ведь например если есть 4 голоса и рейтинг 14, то это вполне может быть:
5+5+2+2
5+5+3+1
5+4+3+2
и т.п.
5+5+3+1
5+4+3+2
и т.п.
Так что вот такая интересная задачка :) Если есть желающие - приглашаю присоединиться к мозговому штурму :)
Судя по всему либо никому не интересно, либо кроме меня большое никто не смог осилить сию задачу.
Ну и ладно. Готовый рабочий вариант кода можно посмотреть у меня в посте
А здесь разберем код построчно :)
Скрипт принимает только 2 параметра:
$vote - количество голосов
$rate - суммарный рейтинг
Заполняем массив единицами (т.е. если бы все поставили по 1 баллу за новость). Размер массива равен количеству голосов.
Сравниваем количество голосов и сумму рейтинга. Проверяем на вероятность оценки в 5 баллов.
Эта строка не обязательна, но я посчитал, что хоть одна оценка, но обяательно должна быть высокой.
Вот же блин, уже и не помню, зачем тут эта строка xD
Тут: $i - простой счетчик, подстраховка от бесконечного цикла. $r - сумма генерируемого рейтинга.
Теперь в цикле будем прибавлять по 1 баллу к оценкам, пока сумма генерируемых оценок не сравняется с исходным значением.
Эта та подстраховка о которой я говорил:
Может это условие и не нужно, но в процессе написания я перепробовал множества вариантов и строка просто осталась, а раз работает то пусть лучше остается :)
А вот и главная фишка :) Зачем эта строка поймете чуть позже (Кто не знает, эта функция перемешивает значения массива)
Перебираем все голоса и их вероятные оценки
То прибавляем к нему единицу и прекращаем цикл foreach
}
}
}
Обнуляем счетчик оценок генерируемого рейтинга и суммируем полученные оценки.
После чего цикл начинается заново, где сравниваются переменные $r - сумма генерируемых оценок и $rate - исходная сумма оценок рейтинга.
}
Таким образом мы получаем массив оценок, где количество элементов строго равно количеству исходных данных голосов. И сумма оценок так же равна исходным данным рейтинга.
Благодаря же shuffle мы получаем, например, не 10 пятерок и 2 двойки, а 8 пятерок, одну четверку, две тройки и одну двойку. Т.е. более равномерное распределение оценок (пример из комментариев).
Ну а это уже подгонка данных под формат для хранения. То, что мне упорно "подсказывали" в комментариях.
Описывать не буду, это уже совсем элементарщина.
Ну и ладно. Готовый рабочий вариант кода можно посмотреть у меня в посте
А здесь разберем код построчно :)
Скрипт принимает только 2 параметра:
$vote - количество голосов
$rate - суммарный рейтинг
Заполняем массив единицами (т.е. если бы все поставили по 1 баллу за новость). Размер массива равен количеству голосов.
$vt = array_fill(0,$vote,1);
Сравниваем количество голосов и сумму рейтинга. Проверяем на вероятность оценки в 5 баллов.
Эта строка не обязательна, но я посчитал, что хоть одна оценка, но обяательно должна быть высокой.
if(($rate-$vote)>=5) $vt[0] = 5;Это своего рода подстраховка того, что нижеописанные скрипт не сделает ни одной высокой оценки.
Вот же блин, уже и не помню, зачем тут эта строка xD
$vt[$vote-1] = 1;
Тут: $i - простой счетчик, подстраховка от бесконечного цикла. $r - сумма генерируемого рейтинга.
$i = 0;
$r = 0;
Теперь в цикле будем прибавлять по 1 баллу к оценкам, пока сумма генерируемых оценок не сравняется с исходным значением.
while($r<$rate){
Эта та подстраховка о которой я говорил:
$i++;
if($i>10000) return "0|0|0|0|0";
Может это условие и не нужно, но в процессе написания я перепробовал множества вариантов и строка просто осталась, а раз работает то пусть лучше остается :)
if($r<$rate){
А вот и главная фишка :) Зачем эта строка поймете чуть позже (Кто не знает, эта функция перемешивает значения массива)
shuffle($vt);
Перебираем все голоса и их вероятные оценки
foreach($vt as $k=>$v){
Проверяем, если оценка (одного голоса) меньше 5и
if($v<5){
То прибавляем к нему единицу и прекращаем цикл foreach
$vt[$k] = $v+1;
break;
}
}
}
Обнуляем счетчик оценок генерируемого рейтинга и суммируем полученные оценки.
$r = 0;
foreach($vt as $v) $r += $v;
После чего цикл начинается заново, где сравниваются переменные $r - сумма генерируемых оценок и $rate - исходная сумма оценок рейтинга.
}
Таким образом мы получаем массив оценок, где количество элементов строго равно количеству исходных данных голосов. И сумма оценок так же равна исходным данным рейтинга.
Благодаря же shuffle мы получаем, например, не 10 пятерок и 2 двойки, а 8 пятерок, одну четверку, две тройки и одну двойку. Т.е. более равномерное распределение оценок (пример из комментариев).
Ну а это уже подгонка данных под формат для хранения. То, что мне упорно "подсказывали" в комментариях.
Описывать не буду, это уже совсем элементарщина.
$votes = array_fill(1,5,0);
foreach($vt as $v) $votes[$v] = $votes[$v]+1;
$votes = implode("|",$votes);
$db->query("UPDATE ".PREFIX."_post SET b_rating='{$votes}' WHERE id={$id}");