В своем комментарии вы говорите, что уникальные средства:
Я не хочу выбирать один и тот же предмет дважды.
..и весы определяют вероятность того, что их выберут.
Все, что вам нужно сделать, чтобы убедиться, что вы не выбираете дубликаты, - это просто удалить последний выбранный элемент из списка, прежде чем выбрать следующий. Да, это немного изменит ваш вес, но это правильное статистическое изменение, если вы хотите получить уникальные результаты.
Кроме того, я не уверен, как вы используете весовые коэффициенты для определения кандидатов, но я придумал этот алгоритм, который должен делать это с минимальным числом циклов (и без необходимости заполнять массив в соответствии с веса, которые могут привести к очень большим массивам, требуют значений int и т. д.)
Я использовал здесь JavaScript, просто чтобы было легко увидеть вывод в браузере без сервера. Это должно быть тривиально портировать на PHP, поскольку он не делает ничего сложного.
Константы
var FRUITS = [
{name : "Apple", weight: 8 },
{name : "Orange", weight: 4 },
{name : "Banana", weight: 4 },
{name : "Nectarine", weight: 3 },
{name : "Kiwi", weight: 1 }
];
var PICKS = 3;
function getNewFruitsAvailable(fruits, removeFruit) {
var newFruits = [];
for (var idx in fruits) {
if (fruits[idx].name != removeFruit) {
newFruits.push(fruits[idx]);
}
}
return newFruits;
}
Сценарий
var results = [];
var candidateFruits = FRUITS;
for (var i=0; i < PICKS; i++) {
// CALCULATE TOTAL WEIGHT OF AVAILABLE FRUITS
var totalweight = 0;
for (var idx in candidateFruits) {
totalweight += candidateFruits[idx].weight;
}
console.log("Total weight: " + totalweight);
var rand = Math.random();
console.log("Random: " + rand);
// ITERATE THROUGH FRUITS AND PICK THE ONE THAT MATCHES THE RANDOM
var weightinc = 0;
for (idx in candidateFruits) {
// INCREMENT THE WEIGHT BY THE NEXT FRUIT'S WEIGHT
var candidate = candidateFruits[idx];
weightinc += candidate.weight;
// IF rand IS BETWEEN LAST WEIGHT AND NEXT WEIGHT, PICK THIS FRUIT
if (rand < weightinc/totalweight) {
results.push(candidate.name);
console.log("Pick: " + candidate.name);
// GET NEXT SET OF FRUITS (REMOVING PICKED FRUIT)
candidateFruits = getNewFruitsAvailable(candidateFruits, candidate.name);
break;
}
}
console.log("CandidateFruits: " + candidateFruits.length);
};
выход
for (var i=0; i < results.length; i++) {
document.write(results[i] + "<br/>");
}
Основная стратегия состоит в том, чтобы выделить каждому фрукту часть общего диапазона [0,1)
. В первом цикле у вас будет это:
- Apple & mdash; 8/20 = 0,0 до 0,4
- Оранжевый & mdash; 4/20 = 0,4 до 0,6
- Банан & mdash; 4/20 = 0,6 до 0,8
- Нектарин & mdash; 3/20 = 0,8 до 0,95
- Киви & mdash; 8/20 = 0,95 до 1,0
Скрипт перебирает каждый элемент в списке и прогрессирует счетчик веса. Когда он достигает диапазона, который содержит первое случайное число, он выбирает этот элемент, удаляет его из списка, затем пересчитывает диапазоны на основе нового общего веса и запускается снова.