Example #1
0
        /// <summary>
        ///     Selects a single item based in the weights
        /// </summary>
        /// <returns>The value of the item</returns>
        public T Select()
        {
            if (_items.Count == 0)
            {
                throw new InvalidOperationException("There was no items to select from");
            }

            Build();

            return(WeightedHelper <T> .SelectItem(_items, _cumulativeWeights, GenerateRandomWeight(_items)).Value);
        }
Example #2
0
        /// <summary>
        ///     Selects multiple items based in the weights
        /// </summary>
        /// <param name="count">The number of items to select</param>
        /// <returns>A list containing the values of the items selected</returns>
        public IEnumerable <T> Select(int count)
        {
            if (count <= 0)
            {
                throw new InvalidOperationException("Count must be > 0.");
            }

            if (_items.Count == 0)
            {
                throw new InvalidOperationException("There were no items to select from.");
            }

            if (!_options.HasFlag(SelectorOptions.AllowDuplicates) && _items.Count < count)
            {
                throw new InvalidOperationException("There aren't enough items in the collection to take " + count);
            }

            Build();

            if (_options.HasFlag(SelectorOptions.AllowDuplicates))
            {
                for (var i = 0; i < count; i++)
                {
                    yield return(WeightedHelper <T>
                                 .SelectItem(_items, _cumulativeWeights, GenerateRandomWeight(_items)).Value);
                }
            }

            // The code bellow can perform under O(log(n)) even when removing items from the list
            // A shallow copy of the lists containing the items and the cumulative weights, since we will be removing items of the list we want to conserve the original ones
            var items   = new List <WeightedItem <T> >(_items);
            var weights = new List <int>(_cumulativeWeightsList);

            for (var i = 0; i < count; i++)
            {
                int index = WeightedHelper <T> .SelectItemIndex(items, weights, GenerateRandomWeight(items));

                if (items.Count > 0)
                {
                    items.RemoveAt(index);
                }

                if (weights.Count > 0)
                {
                    weights.RemoveAt(index);
                }

                yield return(items[index].Value);
            }
        }
Example #3
0
        /// <summary>
        ///     Calculates the cumulative weights if it's needed
        /// </summary>
        public void Build()
        {
            if (!_forceRecalculation)
            {
                return;
            }

            _forceRecalculation = false;
            (_cumulativeWeights, _totalCumulativeWeight) =
                WeightedHelper <T> .CalculateCumulativeWeights(_items, _integerFactor);

            // If the selector don't allow duplicates then it have to create a copy of the weights in list form
            if (!_options.HasFlag(SelectorOptions.AllowDuplicates))
            {
                _cumulativeWeightsList = _cumulativeWeights.ToList();
            }
        }