public static Range <int> EqualRange <TElement, TValue>( [NotNull, ItemNotNull, InstantHandle] this IList <TElement> list, TValue value, int startIndex, int endIndex) where TElement : IComparable <TValue> { Code.NotNull(list, nameof(list)); ValidateIndicesRange(startIndex, endIndex, list.Count); var upperBoundStartIndex = startIndex; var upperBoundEndIndex = endIndex; // the loop locates the lower bound at the same time restricting the range for upper bound search while (startIndex < endIndex) { var median = startIndex + (endIndex - startIndex) / 2; var compareResult = list[median].CompareTo(value); if (compareResult < 0) { startIndex = median + 1; upperBoundStartIndex = startIndex; } else if (compareResult == 0) { endIndex = median; upperBoundStartIndex = endIndex + 1; } else { endIndex = median; upperBoundEndIndex = endIndex; } } return(Range.Create(startIndex, UpperBoundCore(list, value, upperBoundStartIndex, upperBoundEndIndex))); }
public static Range <int> EqualRange( [NotNull, InstantHandle] this IList <float> list, float value, int startIndex, int endIndex) { Code.NotNull(list, nameof(list)); ValidateIndicesRange(startIndex, endIndex, list.Count); var upperBoundStartIndex = startIndex; var upperBoundEndIndex = endIndex; // the loop locates the lower bound at the same time restricting the range for upper bound search while (startIndex < endIndex) { var median = startIndex + (endIndex - startIndex) / 2; if (list[median] < value) { startIndex = median + 1; upperBoundStartIndex = startIndex; } else if (list[median] == value) { endIndex = median; upperBoundStartIndex = endIndex + 1; } else { endIndex = median; upperBoundEndIndex = endIndex; } } return(Range.Create(startIndex, UpperBoundCore(list, value, upperBoundStartIndex, upperBoundEndIndex))); }
/// <summary>Returns first days in range.</summary> /// <param name="range">The date range.</param> /// <returns>First days of months in range</returns> public static IEnumerable <DateTime> DaysBetween(this Range <DateTime> range) { range = range.MakeInclusive(); if (range.IsEmpty) { yield break; } var startDate = range.FromValue; var endDate = range.ToValue; while (startDate <= endDate) { yield return(startDate); startDate = startDate.NextDay(); } }
/// <summary>Splits the range by years.</summary> /// <param name="range">The date range.</param> /// <returns>Ranges split by first day of years in range.</returns> public static IEnumerable <Range <DateTime> > SplitByYears(this Range <DateTime> range) { if (range.IsEmpty) { yield break; } var startDate = range.From.Value; var lastYearDate = range.To.Value.FirstDayOfYear(); while (startDate < lastYearDate) { var next = startDate.FirstDayOfYear().NextYear(); yield return(Range.CreateExclusiveTo(startDate, next)); startDate = next; } yield return(Range.Create(startDate, range.To.Value)); }
public static Range <int> EqualRange <TElement, TValue>( [InstantHandle] this IList <TElement> list, TValue value, [NonNegativeValue] int startIndex, [NonNegativeValue] int endIndex, [InstantHandle] Func <TElement, TValue, int> comparer) { Code.NotNull(list, nameof(list)); Code.NotNull(comparer, nameof(comparer)); ValidateIndicesRange(startIndex, endIndex, list.Count); var upperBoundStartIndex = startIndex; var upperBoundEndIndex = endIndex; // the loop locates the lower bound at the same time restricting the range for upper bound search while (startIndex < endIndex) { var median = startIndex + (endIndex - startIndex) / 2; var compareResult = comparer(list[median], value); switch (compareResult) { case < 0: startIndex = median + 1; upperBoundStartIndex = startIndex; break; case 0: endIndex = median; upperBoundStartIndex = endIndex + 1; break; default: endIndex = median; upperBoundEndIndex = endIndex; break; } } return(Range.Create(startIndex, UpperBoundCore(list, value, upperBoundStartIndex, upperBoundEndIndex, comparer))); }
public static void TestIntersectRanges() { var rangeItems = Enumerable.Range(1, 10) .Cast <int?>() .Select(i => new { From = i % 3 == 0 ? null : 10 * i - 5, To = i % 5 == 0 ? null : 10 * i + 5 }) .OrderBy(x => x.From ?? int.MinValue).ThenBy(x => x.To ?? int.MaxValue) .ToArray(); var ranges = rangeItems.ToCompositeRange(x => x.From, x => x.To); var queryableRanges = rangeItems.AsQueryable(); Assert.AreEqual(queryableRanges.ToArray(), ranges.SubRanges.Select(x => x.Key).ToArray()); Assert.AreEqual( queryableRanges.Intersect(x => x !.From !, x => x !.To !, Range.Create <int?>(5, null)).ToArray(), ranges.Intersect(5, null).SubRanges.Select(x => x.Key).ToArray()); Assert.AreEqual( queryableRanges.Intersect(x => x !.From !, x => x !.To !, Range.Create <int?>(-2, -1)).ToArray(), ranges.Intersect(-2, -1).SubRanges.Select(x => x.Key).ToArray()); Assert.AreEqual( queryableRanges.Intersect(x => x !.From !, x => x !.To !, Range.Create <int?>(null, -1)).ToArray(), ranges.Intersect(null, -1).SubRanges.Select(x => x.Key).ToArray()); Assert.AreEqual( queryableRanges.Intersect(x => x !.From !, x => x !.To !, Range <int?> .Empty).ToArray(), ranges.Intersect(Range <int?> .Empty).SubRanges.Select(x => x.Key).ToArray()); Assert.AreEqual( queryableRanges.Intersect(x => x !.From !, x => x !.To !, Range <int?> .Infinite).ToArray(), ranges.Intersect(Range <int?> .Infinite).SubRanges.Select(x => x.Key).ToArray()); }
/// <summary>Returns first days of years in range.</summary> /// <param name="range">The date range.</param> /// <returns>First days of years in range</returns> public static IEnumerable <DateTime> YearsBetween(this Range <DateTime> range) { range = range.MakeInclusive(); if (range.IsEmpty) { yield break; } var startDate = range.FromValue.FirstDayOfYear(); var endDate = range.ToValue; // if range.FromValue is not first date of year, the years is skipped. if (startDate < range.FromValue) { startDate = startDate.NextYear(); } while (startDate <= endDate) { yield return(startDate); startDate = startDate.NextYear(); } }
/// <summary>Gets date range from start of the year to the current date.</summary> /// <param name="date">The date.</param> /// <returns>Date range.</returns> public static Range <DateTime> GetToEndOfYearRange(this DateTime date) => Range.CreateExclusiveTo(date, date.FirstDayOfYear().NextYear());
/// <summary>Replaces inclusive boundaries with exclusive ones.</summary> /// <param name="range">The date range.</param> /// <returns>A range with inclusive boundaries.</returns> public static Range <DateTime> MakeExclusive(this Range <DateTime> range) => range.MakeExclusive(d => d.PrevDay(), d => d.NextDay());
public static CompositeRange <T> TrimFrom <T>(this CompositeRange <T> compositeRange, T from) => TrimFrom(compositeRange, Range.BoundaryFrom(from));
/// <summary>Gets date range from start of the year to the current date.</summary> /// <param name="date">The date.</param> /// <returns>Date range.</returns> public static Range <DateTime> GetFromStartOfYearRange(this DateTime date) => Range.Create(date.FirstDayOfYear(), date);
public static CompositeRange <T> TrimTo <T>(this CompositeRange <T> compositeRange, T to) => TrimTo(compositeRange, Range.BoundaryTo(to));
/// <summary>Returns date range for month.</summary> /// <param name="date">The date.</param> /// <returns>Date range for month</returns> public static Range <DateTime> GetMonthRange(this DateTime date) => Range.CreateExclusiveTo(date.FirstDayOfMonth(), date.FirstDayOfMonth().NextMonth());
/// <summary>Returns count of month between two dates.</summary> /// <param name="range">The date range.</param> /// <returns>Count of month between two dates.</returns> public static int CountOfMonths(this Range <DateTime> range) => DifferenceInMonths(range) + 1;
public static CompositeRange <T> Except <T>(this CompositeRange <T> compositeRange, T from, T to) => Except(compositeRange, Range.Create(from, to).ToCompositeRange());
public static void TestRangeHasIntersection() { double?empty = null; double?value1 = 1; double?value2 = 2; var emptyFrom = RangeBoundaryFrom <double?> .Empty; var emptyTo = RangeBoundaryTo <double?> .Empty; var range = Range.Create(value1, value2); IsTrue(range.HasIntersection(range)); IsTrue(range.HasIntersection(1, 2)); IsTrue(range.HasIntersection(Range.CreateExclusive(value1, value2, RangeKey2))); IsTrue(range.HasIntersection(1, null)); IsFalse(range.HasIntersection(Range <double?> .Empty)); IsTrue(range.HasIntersection(Range <double?> .Infinite)); IsTrue(range.HasIntersection(null, null)); IsTrue(range.HasIntersection(double.NegativeInfinity, double.PositiveInfinity)); Throws <ArgumentException>( () => range.HasIntersection(2, 1)); Throws <ArgumentException>( () => range.HasIntersection(double.PositiveInfinity, double.NegativeInfinity)); IsTrue(range.HasIntersection(1.5, 1.5)); IsTrue(range.HasIntersection(1.5, 2)); IsTrue(range.HasIntersection(0, 3)); IsTrue(range.HasIntersection(0, 1.5)); IsTrue(range.HasIntersection(1.5, 3)); IsFalse(range.HasIntersection(3, 4)); range = Range.Create(emptyFrom, emptyTo); IsTrue(range.HasIntersection(range)); IsFalse(range.HasIntersection(1, 2)); IsTrue(range.HasIntersection(Range.Create(emptyFrom, emptyTo, RangeKey2))); IsFalse(range.HasIntersection(1, null)); IsTrue(range.HasIntersection(Range <double?> .Empty)); IsFalse(range.HasIntersection(Range <double?> .Infinite)); IsFalse(range.HasIntersection(null, null)); IsFalse(range.HasIntersection(double.NegativeInfinity, double.PositiveInfinity)); Throws <ArgumentException>( () => range.HasIntersection(2, 1)); Throws <ArgumentException>( () => range.HasIntersection(double.PositiveInfinity, double.NegativeInfinity)); range = Range.CreateExclusive(empty, empty); IsTrue(range.HasIntersection(range)); IsTrue(range.HasIntersection(Range.CreateExclusive(empty, empty, RangeKey2))); IsTrue(range.HasIntersection(1, 2)); IsTrue(range.HasIntersection(1, null)); IsFalse(range.HasIntersection(Range <double?> .Empty)); IsTrue(range.HasIntersection(Range <double?> .Infinite)); IsTrue(range.HasIntersection(null, null)); IsTrue(range.HasIntersection(double.NegativeInfinity, double.PositiveInfinity)); Throws <ArgumentException>( () => range.HasIntersection(2, 1)); Throws <ArgumentException>( () => range.HasIntersection(double.PositiveInfinity, double.NegativeInfinity)); range = Range.CreateExclusive(value1, value2); IsTrue(range.HasIntersection(Range.CreateExclusive(value1, value2, RangeKey2))); IsTrue(range.HasIntersection(1, 2)); IsTrue(range.HasIntersection(1.5, 1.5)); IsTrue(range.HasIntersection(1.5, 2)); IsFalse(range.HasIntersection(3, 4)); }
public static void TestRangeStartsAfter() { double?empty = null; double?value1 = 1; double?value2 = 2; var emptyFrom = RangeBoundaryFrom <double?> .Empty; var emptyTo = RangeBoundaryTo <double?> .Empty; var range = Range.Create(value1, value2); IsTrue(range.StartsAfter(null)); IsTrue(range.StartsAfter(double.NegativeInfinity)); IsFalse(range.StartsAfter(double.PositiveInfinity)); IsFalse(range.StartsAfter(RangeBoundaryFrom <double?> .Empty)); IsFalse(range.StartsAfter(RangeBoundaryTo <double?> .Empty)); IsTrue(range.StartsAfter(0)); IsFalse(range.StartsAfter(1)); IsFalse(range.StartsAfter(1.5)); IsFalse(range.StartsAfter(2)); IsFalse(range.StartsAfter(3)); IsTrue(range.StartsAfter(Range.Create(empty, 0, RangeKey2))); IsTrue(range.StartsAfter(Range.CreateExclusiveTo(empty, 1, RangeKey2))); IsFalse(range.StartsAfter(Range.Create(empty, 1, RangeKey2))); range = Range.Create(emptyFrom, emptyTo); IsFalse(range.StartsAfter(null)); IsFalse(range.StartsAfter(double.NegativeInfinity)); IsFalse(range.StartsAfter(double.PositiveInfinity)); IsFalse(range.StartsAfter(RangeBoundaryFrom <double?> .Empty)); IsFalse(range.StartsAfter(RangeBoundaryTo <double?> .Empty)); IsFalse(range.StartsAfter(0)); range = Range.CreateExclusive(empty, empty); IsFalse(range.StartsAfter(null)); IsFalse(range.StartsAfter(double.NegativeInfinity)); IsFalse(range.StartsAfter(double.PositiveInfinity)); IsFalse(range.StartsAfter(RangeBoundaryFrom <double?> .Empty)); IsFalse(range.StartsAfter(RangeBoundaryTo <double?> .Empty)); IsFalse(range.StartsAfter(0)); range = Range.CreateExclusive(value1, value2); IsTrue(range.StartsAfter(1)); IsFalse(range.StartsAfter(1.5)); IsFalse(range.StartsAfter(2)); range = Range.CreateExclusive(value1, value2); IsTrue(range.StartsAfter(Range.BoundaryFrom <double?>(1))); IsFalse(range.StartsAfter(Range.BoundaryTo <double?>(2))); IsFalse(range.StartsAfter(Range.BoundaryFromExclusive <double?>(1))); IsFalse(range.StartsAfter(Range.BoundaryFromExclusive <double?>(1.5))); IsFalse(range.StartsAfter(Range.BoundaryFromExclusive <double?>(2))); IsTrue(range.StartsAfter(Range.BoundaryToExclusive <double?>(1))); IsFalse(range.StartsAfter(Range.BoundaryToExclusive <double?>(1.5))); IsFalse(range.StartsAfter(Range.BoundaryToExclusive <double?>(2))); Throws <ArgumentException>( () => range.StartsAfter(Range.BoundaryFrom <double?>(double.PositiveInfinity))); Throws <ArgumentException>( () => range.StartsAfter(Range.BoundaryTo <double?>(double.NegativeInfinity))); }
/// <summary>Creates instance of <seealso cref="Range{T}"/></summary> /// <param name="from">Boundary From.</param> /// <param name="to">Boundary To.</param> /// <param name="key">The value of the range key.</param> public Range(T from, T to, TKey key) : this(Range.BoundaryFrom(from), Range.BoundaryTo(to), key) { }
/// <summary>Creates instance of <seealso cref="Range{T}"/></summary> /// <param name="from">Boundary From.</param> /// <param name="to">Boundary To.</param> public Range(T from, T to) : this(Range.BoundaryFrom(from), Range.BoundaryTo(to)) { }
public static CompositeRange <T> Except <T, TKey2>(this CompositeRange <T> compositeRange, Range <T, TKey2> other) => Except(compositeRange, other.ToCompositeRange());
/// <summary>Returns count of days between two dates.</summary> /// <param name="range">The date range.</param> /// <returns>Count of days between two dates.</returns> public static int CountOfDays(this Range <DateTime> range) => DifferenceInDays(range) + 1;
public static CompositeRange <T> Intersect <T>(this CompositeRange <T> compositeRange, T from, T to) => Intersect(compositeRange, Range.Create(from, to).ToCompositeRange());
/// <summary>Returns delta between two dates measured in months.</summary> /// <param name="range">The date range.</param> /// <returns>Delta between two dates measured in months.</returns> public static int DifferenceInMonths(this Range <DateTime> range) { range = range.MakeInclusive(); return(DifferenceInMonths(range.FromValue, range.ToValue)); }
public static CompositeRange <T> TrimTo <T>(this CompositeRange <T> compositeRange, RangeBoundaryTo <T> to) => compositeRange.Intersect(Range.TryCreate(RangeBoundaryFrom <T> .NegativeInfinity, to));
public static CompositeRange <T> Intersect <T, TKey2>(this CompositeRange <T> compositeRange, Range <T, TKey2> other) => Intersect(compositeRange, other.ToCompositeRange());
public static CompositeRange <T> Union <T>(this CompositeRange <T> compositeRange, Range <T> other) => Union(compositeRange, other.ToCompositeRange());
public static void TestRangeEndsBefore() { double?empty = null; double?value1 = 1; double?value2 = 2; var emptyFrom = RangeBoundaryFrom <double?> .Empty; var emptyTo = RangeBoundaryTo <double?> .Empty; var range = Range.Create(value1, value2); IsTrue(range.EndsBefore(null)); IsFalse(range.EndsBefore(double.NegativeInfinity)); IsTrue(range.EndsBefore(double.PositiveInfinity)); IsFalse(range.EndsBefore(RangeBoundaryFrom <double?> .Empty)); IsFalse(range.EndsBefore(RangeBoundaryTo <double?> .Empty)); IsFalse(range.EndsBefore(0)); IsFalse(range.EndsBefore(1)); IsFalse(range.EndsBefore(1.5)); IsFalse(range.EndsBefore(2)); IsTrue(range.EndsBefore(3)); IsFalse(range.EndsBefore(Range.Create(2, empty, RangeKey2))); IsTrue(range.EndsBefore(Range.CreateExclusiveFrom(2, empty, RangeKey2))); IsTrue(range.EndsBefore(Range.Create(3, empty, RangeKey2))); range = Range.Create(emptyFrom, emptyTo); IsFalse(range.EndsBefore(null)); IsFalse(range.EndsBefore(double.NegativeInfinity)); IsFalse(range.EndsBefore(double.PositiveInfinity)); IsFalse(range.EndsBefore(RangeBoundaryFrom <double?> .Empty)); IsFalse(range.EndsBefore(RangeBoundaryTo <double?> .Empty)); IsFalse(range.EndsBefore(0)); range = Range.CreateExclusive(empty, empty); IsFalse(range.EndsBefore(null)); IsFalse(range.EndsBefore(double.NegativeInfinity)); IsFalse(range.EndsBefore(double.PositiveInfinity)); IsFalse(range.EndsBefore(RangeBoundaryFrom <double?> .Empty)); IsFalse(range.EndsBefore(RangeBoundaryTo <double?> .Empty)); IsFalse(range.EndsBefore(0)); range = Range.CreateExclusive(value1, value2); IsFalse(range.EndsBefore(1)); IsFalse(range.EndsBefore(1.5)); IsTrue(range.EndsBefore(2)); range = Range.CreateExclusive(value1, value2); IsFalse(range.EndsBefore(Range.BoundaryFrom <double?>(1))); IsTrue(range.EndsBefore(Range.BoundaryTo <double?>(2))); IsFalse(range.EndsBefore(Range.BoundaryFromExclusive <double?>(1))); IsFalse(range.EndsBefore(Range.BoundaryFromExclusive <double?>(1.5))); IsTrue(range.EndsBefore(Range.BoundaryFromExclusive <double?>(2))); IsFalse(range.EndsBefore(Range.BoundaryToExclusive <double?>(1))); IsFalse(range.EndsBefore(Range.BoundaryToExclusive <double?>(1.5))); IsFalse(range.EndsBefore(Range.BoundaryToExclusive <double?>(2))); Throws <ArgumentException>( () => range.EndsBefore(Range.BoundaryFrom <double?>(double.PositiveInfinity))); Throws <ArgumentException>( () => range.EndsBefore(Range.BoundaryTo <double?>(double.NegativeInfinity))); }
public static CompositeRange <T> TrimFrom <T>(this CompositeRange <T> compositeRange, RangeBoundaryFrom <T> from) => compositeRange.Intersect(Range.TryCreate(from, RangeBoundaryTo <T> .PositiveInfinity));
/// <summary>Creates the composite range.</summary> /// <typeparam name="T">The type of the range values.</typeparam> /// <typeparam name="TKey">The type of the range key</typeparam> /// <param name="range">The range.</param> /// <returns>A new composite range.</returns> public static CompositeRange <T, TKey> Create <T, TKey>(Range <T, TKey> range) => new CompositeRange <T, TKey>(range);
public static bool HasIntersection <T, TKey2>( this CompositeRange <T> compositeRange, Range <T, TKey2> other) => compositeRange.ContainingRange.HasIntersection(other) && compositeRange.SubRanges.Any(r => r.HasIntersection(other));