あなたのコメントでは、一意の意味は次のとおりです。
同じものは二度と選びたくない。
..そして、重みが選ばれる可能性を決定すること。
重複を選択しないようにするために必要なことは、次のアイテムを選択する前に、最後に選択したアイテムをリストから削除することだけです。はい、これにより重みがわずかに変更されますが、一意の結果が必要な場合は、これが正しい統計変更です。
さらに、候補を決定するために重みをどのように使用しているかはわかりませんが、最小数のループでこれを行う必要があるこのアルゴリズムを思いつきました (重みに従って配列を埋める必要はありません。非常に大きな配列になる可能性があり、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)
。最初のループでは、次のようになります。
- りんご— 8/20 = 0.0 ~ 0.4
- オレンジ— 4/20 = 0.4 ~ 0.6
- バナナ— 4/20 = 0.6 ~ 0.8
- ネクタリン— 3/20 = 0.8 ~ 0.95
- キーウィ— 8/20 = 0.95 ~ 1.0
スクリプトはリスト内の各項目を繰り返し処理し、重量カウンターを進めます。最初の乱数を含む範囲に到達すると、そのアイテムが選択され、リストから削除され、新しい総重量に基づいて範囲が再計算され、再度実行されます。