public static IEnumerable <TKey> GetKeyRangeBetween <TKey, TValue>(this SortedList <TKey, TValue> sortedList, TKey low, TKey high) { int lowIndex = sortedList.BinarySearch(low); if (lowIndex < 0) { // list doesn't contain the key, find nearest behind // If not found, BinarySearch returns the complement of the index lowIndex = ~lowIndex; } int highIndex = sortedList.BinarySearch(high); if (highIndex < 0) { // list doesn't contain the key, find nearest before // If not found, BinarySearch returns the complement of the index highIndex = ~highIndex - 1; } var keys = sortedList.Keys; for (int i = lowIndex; i < highIndex; i++) { yield return(keys[i]); } }
/// <summary> /// Binary searches one of the control point lists to find the active control point at <paramref name="time"/>. /// </summary> /// <param name="list">The list to search.</param> /// <param name="time">The time to find the control point at.</param> /// <param name="prePoint">The control point to use when <paramref name="time"/> is before any control points. If null, a new control point will be constructed.</param> /// <returns>The active control point at <paramref name="time"/>.</returns> private T binarySearch <T>(SortedList <T> list, double time, T prePoint = null) where T : ControlPoint, new() { if (list.Count == 0) { return(new T()); } if (time < list[0].Time) { return(prePoint ?? new T()); } int index = list.BinarySearch(new T { Time = time }); // Check if we've found an exact match (t == time) if (index >= 0) { return(list[index]); } index = ~index; // BinarySearch will return the index of the first element _greater_ than the search // This is the inactive point - the active point is the one before it (index - 1) return(list[index - 1]); }
/// <summary> /// Retrieves the value of the series at a specified point in time. See Remarks for /// info on interpolation modes. /// </summary> /// <remarks> /// <para> /// When the specified key does not exist in the data set, <see cref="Get"/> will /// interpolate or extrapolate as necessary. This can be prevented by using interpolation /// mode "None", in which case an exception will be thrown instead. /// </para> /// <para> /// If extrapolation is required, this method will always extrapolate to the nearest /// available value. For example, the series "5, 8, 12" would be extrapolated as "5, 5, 5, 8, 12, 12, 12". /// </para> /// </remarks> /// <param name="time"></param> /// <param name="interpolation"></param> public decimal Get(DateTime time, GncInterpolation interpolation) { if (time.Kind != DateTimeKind.Utc) { throw new RTException("DateTime passed to GncTimeSeries.Get must be a UTC time."); } if (_data.Count == 0) { throw new InvalidOperationException("Cannot Get a value from an empty GncTimeSeries."); } if (interpolation == GncInterpolation.None) { return(_data[time]); // Throws if not found, as desired for this interpolation type } int index1, index2; _data.BinarySearch(time, out index1, out index2); if (index1 == index2) { return(_data.Values[index1]); // Found the key we're looking for } if (index1 == int.MinValue) { return(_data.Values[index2]); // Must extrapolate to the left } if (index2 == int.MaxValue) { return(_data.Values[index1]); // Must extrapolate to the right } if (interpolation == GncInterpolation.NearestBefore) { return(_data.Values[index1]); } else if (interpolation == GncInterpolation.NearestAfter) { return(_data.Values[index2]); } else if (interpolation == GncInterpolation.Nearest) { var spanL = time - _data.Keys[index1]; var spanR = _data.Keys[index2] - time; return((spanL <= spanR) ? _data.Values[index1] : _data.Values[index2]); } else if (interpolation == GncInterpolation.Linear) { decimal spanL = (decimal)(time - _data.Keys[index1]).Ticks; decimal spanR = (decimal)(_data.Keys[index2] - time).Ticks; decimal valL = _data.Values[index1]; decimal valR = _data.Values[index2]; return(valL + (valR - valL) * spanL / (spanL + spanR)); } throw new NotImplementedException(); // if new interpolation modes are added }
public void TestBinarySearch() { Assert.Throws <ArgumentNullException>(() => { int i1, i2; CollectionExtensions.BinarySearch <string, string>(null, null, out i1, out i2); }); Assert.Throws <ArgumentNullException>(() => { int i1, i2; CollectionExtensions.BinarySearch <string, string>(new SortedList <string, string>(), null, out i1, out i2); }); Assert.Throws <ArgumentNullException>(() => { int i1, i2; CollectionExtensions.BinarySearch <string, string>(null, "", out i1, out i2); }); Assert.DoesNotThrow(() => { int i1, i2; CollectionExtensions.BinarySearch <string, string>(new SortedList <string, string>(), "", out i1, out i2); }); SortedList <int, string> list = new SortedList <int, string>(); Action <int, int, int> assert = (int key, int index1, int index2) => { int i1, i2; list.BinarySearch(key, out i1, out i2); Assert.AreEqual(index1, i1); Assert.AreEqual(index2, i2); }; assert(5, int.MinValue, int.MaxValue); list.Add(5, "five"); // 5 assert(4, int.MinValue, 0); assert(5, 0, 0); assert(6, 0, int.MaxValue); list.Add(6, "six"); // 5, 6 assert(4, int.MinValue, 0); assert(5, 0, 0); assert(6, 1, 1); assert(7, 1, int.MaxValue); list.Add(3, "three"); // 3, 5, 6 assert(2, int.MinValue, 0); assert(3, 0, 0); assert(4, 0, 1); assert(5, 1, 1); assert(6, 2, 2); assert(7, 2, int.MaxValue); list.Add(15, "fifteen"); // 3, 5, 6, 15 assert(2, int.MinValue, 0); assert(3, 0, 0); assert(4, 0, 1); assert(5, 1, 1); assert(6, 2, 2); assert(7, 2, 3); assert(11, 2, 3); assert(14, 2, 3); assert(15, 3, 3); assert(16, 3, int.MaxValue); assert(-999999999, int.MinValue, 0); assert(999999999, 3, int.MaxValue); }
public static IEnumerable <KeyValuePair <TKey, TValue> > GetElementsGreaterThanOrEqual <TKey, TValue>(this SortedList <TKey, TValue> instance, TKey target) where TKey : IComparable <TKey> { int index = instance.BinarySearch(target); if (index < 0) { index = ~index; } for (int i = index; i < instance.Count; i++) { yield return(new KeyValuePair <TKey, TValue>(instance.Keys[i], instance.Values[i])); } }
/// <summary> /// Built-in binary search. /// Time complexity: O(n log n). /// Space complexity: O(n). /// </summary> public override void AddNum(int num) { var index = SortedList.BinarySearch(num); if (index < 0) { SortedList.Insert(~index, num); } else { SortedList.Insert(index, num); } }
/// <summary> /// Generates a <see cref="MultiplierControlPoint"/> with the default timing change/difficulty change from the beatmap at a time. /// </summary> /// <param name="time">The time to create the control point at.</param> /// <returns>The default <see cref="MultiplierControlPoint"/> at <paramref name="time"/>.</returns> public MultiplierControlPoint CreateControlPointAt(double time) { if (DefaultControlPoints.Count == 0) { return(new MultiplierControlPoint(time)); } int index = DefaultControlPoints.BinarySearch(new MultiplierControlPoint(time)); if (index < 0) { return(new MultiplierControlPoint(time)); } return(new MultiplierControlPoint(time, DefaultControlPoints[index])); }
/// <summary> /// Finds the <see cref="MultiplierControlPoint"/> which affects the speed of hitobjects at a specific time. /// </summary> /// <param name="time">The time which the <see cref="MultiplierControlPoint"/> should affect.</param> /// <returns>The <see cref="MultiplierControlPoint"/>.</returns> private MultiplierControlPoint controlPointAt(double time) { if (controlPoints.Count == 0) { return(new MultiplierControlPoint(double.NegativeInfinity)); } if (time < controlPoints[0].StartTime) { return(controlPoints[0]); } searchPoint.StartTime = time; int index = controlPoints.BinarySearch(searchPoint); if (index < 0) { index = ~index - 1; } return(controlPoints[index]); }
public double ReturnTSLoad(DateTime TimeIndex) { if (!ITSI_Translated) { Translate_ITimeSeriesInput(); } double RetLoad; DateTime TIHolder; { RetLoad = 0; bool foundopt = false; if ((list != null) && (list.Count != 0)) { if (lastindexread > -1) { if (list.Keys[lastindexread] == TimeIndex) { RetLoad = list.Values[lastindexread]; foundopt = true; } else if (lastindexread < list.Count - 2) { if (list.Keys[lastindexread + 1] == TimeIndex) { RetLoad = list.Values[lastindexread + 1]; foundopt = true; lastindexread = lastindexread + 1; } } } if (!foundopt) { TIHolder = TimeIndex; if (!Hourly) { TIHolder = TimeIndex.Date; } int indx = list.BinarySearch(TIHolder); if (indx >= 0) { RetLoad = list.Values[indx]; lastindexread = indx; } else { // This procedure calculates the time-series loading for a given timeindex. // If there is only one time-series loading point present, that is essentially // the same thing as a constant load, no further data are available. // // If there is more than one point, then the procedure linearly interpolates // the correct loading for the time index.A year cycle is also assumed for // loading.If the timeindex is between two points, a straight linear interpolation // is done.If the timeindex is not between two points, // it is moved forward or backward by 1 year increments to try // and get it between two points. If necessary another "dummy" loading is added // after the timeindex to make interpolation possible. (if jumping does not // place the point within two points} if (list.Count == 0) { RetLoad = 0; } else { // Four Cases, (1) TimeIndex before all loading dates, // (2) TimeIndex after all loading dates, // (3) TimeIndex in the middle of 2 loading dates // (4) TimeIndex = Loading Date.} if (indx == ~list.Count) // {case 2} { do // Move TimeIndex back to create case 1,3, or 4 { TIHolder = TIHolder.AddYears(-1); indx = list.BinarySearch(TIHolder); }while (indx == ~list.Count); } // Try to Translate Case 1 into Case 3 or 4 by Moving TimeIndex up. // May jump all loadings and create case 2} if (indx == -1) { do // Move TimeIndex forward to create case 2,3, or 4} { TIHolder = TIHolder.AddYears(1); indx = list.BinarySearch(TIHolder); }while (indx == -1); } if (indx == ~list.Count) // Jumped to Case 2, Need to Add "New" Load at end for interpolation { do { list.Add(list.Keys[0].AddYears(1), list.Values[0]); indx = list.BinarySearch(TIHolder); }while (indx == ~list.Count); } if (indx >= 0) { RetLoad = list.Values[indx]; lastindexread = indx; } else { indx = ~indx; // Case 3, Linear Interpolation between TLoad[i - 1] (x1, y1), and TLoad[i] (x2, y2) double y1, y2; DateTime x1, x2; y1 = list.Values[indx - 1]; x1 = list.Keys[indx - 1]; y2 = list.Values[indx]; x2 = list.Keys[indx]; double m = (y2 - y1) / (x2 - x1).TotalDays; RetLoad = m * (TIHolder - x1).TotalDays + y1; } } } } } } return(RetLoad); }
public void TestBinarySearch() { Assert.Throws<ArgumentNullException>(() => { int i1, i2; CollectionExtensions.BinarySearch<string, string>(null, null, out i1, out i2); }); Assert.Throws<ArgumentNullException>(() => { int i1, i2; CollectionExtensions.BinarySearch<string, string>(new SortedList<string, string>(), null, out i1, out i2); }); Assert.Throws<ArgumentNullException>(() => { int i1, i2; CollectionExtensions.BinarySearch<string, string>(null, "", out i1, out i2); }); Assert.DoesNotThrow(() => { int i1, i2; CollectionExtensions.BinarySearch<string, string>(new SortedList<string, string>(), "", out i1, out i2); }); SortedList<int, string> list = new SortedList<int, string>(); Action<int, int, int> assert = (int key, int index1, int index2) => { int i1, i2; list.BinarySearch(key, out i1, out i2); Assert.AreEqual(index1, i1); Assert.AreEqual(index2, i2); }; assert(5, int.MinValue, int.MaxValue); list.Add(5, "five"); // 5 assert(4, int.MinValue, 0); assert(5, 0, 0); assert(6, 0, int.MaxValue); list.Add(6, "six"); // 5, 6 assert(4, int.MinValue, 0); assert(5, 0, 0); assert(6, 1, 1); assert(7, 1, int.MaxValue); list.Add(3, "three"); // 3, 5, 6 assert(2, int.MinValue, 0); assert(3, 0, 0); assert(4, 0, 1); assert(5, 1, 1); assert(6, 2, 2); assert(7, 2, int.MaxValue); list.Add(15, "fifteen"); // 3, 5, 6, 15 assert(2, int.MinValue, 0); assert(3, 0, 0); assert(4, 0, 1); assert(5, 1, 1); assert(6, 2, 2); assert(7, 2, 3); assert(11, 2, 3); assert(14, 2, 3); assert(15, 3, 3); assert(16, 3, int.MaxValue); assert(-999999999, int.MinValue, 0); assert(999999999, 3, int.MaxValue); }
/// <summary>Determines whether an <seealso cref="GuidelineEditorPresetEvent"/> is contained in the track.</summary> /// <param name="e">The <seealso cref="GuidelineEditorPresetEvent"/> to check whether it is contained in the track.</param> public bool Contains(GuidelineEditorPresetEvent e) => events.BinarySearch(e) > -1;
/// <summary>Returns the index of the specified <seealso cref="TimingPoint"/> in the list.</summary> /// <param name="timingPoint">The <seealso cref="TimingPoint"/> whose index in the list to get.</param> public int IndexOf(TimingPoint timingPoint) => timingPoints.BinarySearch(timingPoint);