public void Add(T item, int priority = 0) { int oldPriority; if (sub.UpdateOrAdd(item, priority, out oldPriority)) { RemoveMain(oldPriority, item); } if (reserveList == null) { reserveList = new HashedLinkedList <T>(cmp); } var list = reserveList; if (!main.FindOrAdd(priority, ref list)) { reserveList = null; } list.Add(item); }
/// <summary> /// Add a new value to the T-Digest. Note that this method is NOT thread safe. /// </summary> /// <param name="value">The value to add</param> /// <param name="weight">The relative weight associated with this value. Default is 1 for all values.</param> public void Add(double value, double weight = 1) { if (weight <= 0) { throw new ArgumentOutOfRangeException(nameof(weight), "must be greater than 0"); } var first = count == 0; count += weight; if (first) { oldAvg = value; newAvg = value; Min = value; Max = value; } else { newAvg = oldAvg + (value - oldAvg) / count; oldAvg = newAvg; Max = value > Max ? value : Max; Min = value < Min ? value : Min; } if (centroids.Count == 0) { centroids.Add(value, new Centroid(value, weight)); return; } var closest = GetClosestCentroids(value); var candidates = closest .Select(c => new { Threshold = GetThreshold(ComputeCentroidQuantile(c)), Centroid = c }) .Where(c => c.Centroid.Count + weight < c.Threshold) .ToList(); while (candidates.Count > 0 & weight > 0) { var cData = candidates[_rand.Next() % candidates.Count]; var deltaW = Math.Min(cData.Threshold - cData.Centroid.Count, weight); double oldMean; if (cData.Centroid.Update(deltaW, value, out oldMean)) { ReInsertCentroid(oldMean, cData.Centroid); } weight -= deltaW; candidates.Remove(cData); } if (weight > 0) { var toAdd = new Centroid(value, weight); if (centroids.FindOrAdd(value, ref toAdd)) { double oldMean; if (toAdd.Update(weight, toAdd.Mean, out oldMean)) { ReInsertCentroid(oldMean, toAdd); } } } if (centroids.Count > (CompressionConstant / Accuracy)) { Compress(); } }