From 9b8209f50ae27d756765ed03a545a0cec720a51e Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Fri, 21 Aug 2026 12:16:12 +0000 Subject: [PATCH] perf(CollectionExtensions): optimize WeightedRandom to avoid array allocation Co-authored-by: johnstrand <11484777+johnstrand@users.noreply.github.com> --- .../Extensions/CollectionExtensions.cs | 41 +++++++++---------- 1 file changed, 19 insertions(+), 22 deletions(-) diff --git a/src/GameUtils/Extensions/CollectionExtensions.cs b/src/GameUtils/Extensions/CollectionExtensions.cs index bc27b99..e1efe78 100644 --- a/src/GameUtils/Extensions/CollectionExtensions.cs +++ b/src/GameUtils/Extensions/CollectionExtensions.cs @@ -245,37 +245,34 @@ public static T WeightedRandom(this IEnumerable source, Func wei return list[count - 1]; } - var array = source.ToArray(); - int arrayCount = array.Length; - if (arrayCount == 0) - { - throw new InvalidOperationException("Sequence contains no elements."); - } + T selected = default!; + float fallbackTotalWeight = 0f; + bool hasElements = false; - var arrayTotalWeight = 0f; - for (int i = 0; i < arrayCount; i++) + foreach (var item in source) { - arrayTotalWeight += weightSelector(array[i]); + hasElements = true; + float weight = weightSelector(item); + if (weight <= 0f) continue; + + fallbackTotalWeight += weight; + + if (Random.Shared.NextDouble() * fallbackTotalWeight < weight) + { + selected = item; + } } - if (arrayTotalWeight <= 0) + if (!hasElements) { - throw new InvalidOperationException("Total weight must be greater than zero."); + throw new InvalidOperationException("Sequence contains no elements."); } - var arrayTarget = (float)(Random.Shared.NextDouble() * arrayTotalWeight); - var arrayCumulative = 0f; - - for (int i = 0; i < arrayCount; i++) + if (fallbackTotalWeight <= 0f) { - var item = array[i]; - arrayCumulative += weightSelector(item); - if (arrayTarget <= arrayCumulative) - { - return item; - } + throw new InvalidOperationException("Total weight must be greater than zero."); } - return array[arrayCount - 1]; + return selected; } }