Вы писали:
, придавая значение кредитам с более высокой стоимостью
Означает ли это, что, если у вас есть не показанные объявления с кредитом 40, вывообще не хотите показывать рекламу с кредитом 10?Или вы имеете в виду, что вы хотите, чтобы объявления с более высокими кредитами имели более высокий шанс показа.И если так: если кредиты в 4 раза выше, должен ли шанс быть показан в четыре раза больше?
Давайте предположим, что вы не хотите показывать объявления с более низкими кредитами, пока вы не показывалиобъявления с более высоким кредитом.
int nrOfAdsToSelect = ...;
var selectedAds = dbContext.Adds
.Where(ad => !ad.IsSelected)
.OrderyDescending(ad => ad.Credit)
.Take(nrOfAddsToSelect);
Однако, если вы хотите, чтобы все объявления имели возможность показа, только объявления с более высоким кредитом имеют более высокий шанс, вам следует подумать о том, насколько выше этот шанс.
Проще всего было бы перевести кредит в диапазон целых чисел, указывающих, когда нужно выбрать объявление:
Id Credit => Range
00 01 00
01 01 01
02 02 02, 03 // credit 2: 2 numbers
03 03 04, 05, 06 // credit 3: 3 numbers
04 10 07, 08, 09, 10, 11, 12, 13, 14, 15, 16 // 10 numbers
Возьмите случайное число в диапазоне [00, 16].Вероятность того, что выбран идентификатор Id 04, в 10 раз выше, чем вероятность выбора идентификатора 01.
Итак, вам нужна функция для создания целочисленного диапазона из Credit и StartNumber.Это может быть так же просто, как указано выше, это может быть любой другой алгоритм, в зависимости от того, насколько вы оцениваете шансы объявлений с более высоким кредитом.
Вы можете использовать свою функцию кредитования в диапазон, чтобы преобразовать последовательность не-displayed Добавляет в последовательность целых чисел.
В качестве функций расширения:
static IEnumerable<int> ToRange(this int credit, int startNumber)
{
// example: Credit 40 is 40 times more chance than credit 1.
// so range length is equal to credit
return Enumerable.Range(startNumber, credit);
}
static IEnumerable<int> ToRange(this IEnumerable<Ad> adds)
{
int startNumber = 0;
foreach (Ad add in adds)
{
// only use ads that are not displayed yet to select a new Ad.
if (!ad.IsDisplayed)
{
var range = add.Credit.ToRange();
foreach (var value in range) yield return value;
}
}
}
Использование:
List<Ad> ads = ...
var range = ads.ToRange().ToList();
int selectedIndex = rnd.Next(range.Count);
var firstSelectedAdd = ads[selectedIndex];
Проблема в том, что, как только вы выбралиВаше первое объявление, шансы вашего второго объявления должны измениться.Вам нужно будет создать новый диапазон:
static Ad Select(this IReadOnlyList<Ad> ads)
{
var range = ads.ToRange().ToList();
int selectedIndex = rnd.Next(range.Count);
return ads[selectedIndex];
}
static IEnumerable<Ad> SelectAds(this IEnumerable<Ad> ads, int selectCount)
{
for (int i=0; i<selectCount; ++i)
{
var selectedAd = ads.Select();
yield return selectedAd;
selectedAd.IsDisplayed = true; // to make sure it is not selected again
}
}