From 9a53bc3e576d28382e4530925297f66cecf2129f Mon Sep 17 00:00:00 2001 From: Flaminel Date: Fri, 23 Oct 2026 02:11:49 +0300 Subject: [PATCH] removed duplicated weighted sampling loop from selectors --- .../Selectors/BalancedWeightedSelector.cs | 29 +------------------ .../CustomFormatGapWeightedSelector.cs | 29 +------------------ .../Selectors/OldestSearchWeightedSelector.cs | 11 ++++++- 3 files changed, 12 insertions(+), 57 deletions(-) diff --git a/code/backend/Cleanuparr.Infrastructure/Features/Seeker/Selectors/BalancedWeightedSelector.cs b/code/backend/Cleanuparr.Infrastructure/Features/Seeker/Selectors/BalancedWeightedSelector.cs index 466fff06..a59263cb 100644 --- a/code/backend/Cleanuparr.Infrastructure/Features/Seeker/Selectors/BalancedWeightedSelector.cs +++ b/code/backend/Cleanuparr.Infrastructure/Features/Seeker/Selectors/BalancedWeightedSelector.cs @@ -30,37 +30,10 @@ public sealed class BalancedWeightedSelector : IItemSelector .ToDictionary(x => x.Id, x => x.Rank); // Composite weight = average of both ranks (higher = more likely to be selected) - var selected = new List(count); var pool = candidates .Select(c => (c.Id, Weight: (searchRanks[c.Id] + ageRanks[c.Id]) / 2.0)) .ToList(); - for (int i = 0; i < count && pool.Count > 0; i++) - { - double totalWeight = 0; - for (int j = 0; j < pool.Count; j++) - { - totalWeight += pool[j].Weight; - } - - double target = Random.Shared.NextDouble() * totalWeight; - double cumulative = 0; - int selectedIndex = pool.Count - 1; - - for (int j = 0; j < pool.Count; j++) - { - cumulative += pool[j].Weight; - if (cumulative >= target) - { - selectedIndex = j; - break; - } - } - - selected.Add(pool[selectedIndex].Id); - pool.RemoveAt(selectedIndex); - } - - return selected; + return OldestSearchWeightedSelector.WeightedRandom(pool, count); } } diff --git a/code/backend/Cleanuparr.Infrastructure/Features/Seeker/Selectors/CustomFormatGapWeightedSelector.cs b/code/backend/Cleanuparr.Infrastructure/Features/Seeker/Selectors/CustomFormatGapWeightedSelector.cs index 8f85fa39..acafdde2 100644 --- a/code/backend/Cleanuparr.Infrastructure/Features/Seeker/Selectors/CustomFormatGapWeightedSelector.cs +++ b/code/backend/Cleanuparr.Infrastructure/Features/Seeker/Selectors/CustomFormatGapWeightedSelector.cs @@ -25,37 +25,10 @@ public sealed class CustomFormatGapWeightedSelector : IItemSelector double maxGap = candidates.Max(c => c.Gap); // The recency half is at least 1/n, so every weight stays above zero - List selected = new(count); List<(long Id, double Weight)> pool = candidates .Select(c => (c.Id, Weight: 0.5 * (maxGap > 0 ? c.Gap / maxGap : 0) + 0.5 * searchRanks[c.Id] / n)) .ToList(); - for (int i = 0; i < count && pool.Count > 0; i++) - { - double totalWeight = 0; - for (int j = 0; j < pool.Count; j++) - { - totalWeight += pool[j].Weight; - } - - double target = Random.Shared.NextDouble() * totalWeight; - double cumulative = 0; - int selectedIndex = pool.Count - 1; - - for (int j = 0; j < pool.Count; j++) - { - cumulative += pool[j].Weight; - if (cumulative >= target) - { - selectedIndex = j; - break; - } - } - - selected.Add(pool[selectedIndex].Id); - pool.RemoveAt(selectedIndex); - } - - return selected; + return OldestSearchWeightedSelector.WeightedRandom(pool, count); } } diff --git a/code/backend/Cleanuparr.Infrastructure/Features/Seeker/Selectors/OldestSearchWeightedSelector.cs b/code/backend/Cleanuparr.Infrastructure/Features/Seeker/Selectors/OldestSearchWeightedSelector.cs index f7a1934b..71f7782d 100644 --- a/code/backend/Cleanuparr.Infrastructure/Features/Seeker/Selectors/OldestSearchWeightedSelector.cs +++ b/code/backend/Cleanuparr.Infrastructure/Features/Seeker/Selectors/OldestSearchWeightedSelector.cs @@ -33,7 +33,6 @@ public sealed class OldestSearchWeightedSelector : IItemSelector int count) { int n = ranked.Count; - var selected = new List(count); // Build initial weights from rank: highest rank (index 0) gets weight N, lowest gets 1 var pool = new List<(long Id, double Weight)>(n); @@ -42,6 +41,16 @@ public sealed class OldestSearchWeightedSelector : IItemSelector pool.Add((ranked[i].Id, n - i)); } + return WeightedRandom(pool, count); + } + + /// + /// Performs weighted random selection without replacement. Consumes . + /// + internal static List WeightedRandom(List<(long Id, double Weight)> pool, int count) + { + List selected = new(count); + for (int i = 0; i < count && pool.Count > 0; i++) { double totalWeight = 0;