DiscreteInterval<T> Struct
Definition
- Assembly
- Bodu.Numerics.dll
- Package
- Bodu.Numerics 1.0.0
Represents an immutable interval over a discrete integer domain - a set of consecutive integers of type
T - with successor/predecessor-aware emptiness and adjacency.
public readonly struct DiscreteInterval<T> : ISpanFormattable, IFormattable, IUtf8SpanFormattable, IEquatable<DiscreteInterval<T>> where T : IBinaryInteger<T>
Type Parameters
TThe integer type used for the interval's endpoints.
- Implements
- Inherited Members
- Extension Methods
Examples
using Bodu.Numerics;
DiscreteInterval<int>.Open(1, 2).IsEmpty; // True - no integer strictly between 1 and 2
var a = DiscreteInterval<int>.Closed(1, 2);
var b = DiscreteInterval<int>.Closed(3, 4);
a.TryUnion(b, out var run); // run = [1, 4], result = true (successor-adjacent)
DiscreteInterval<int>.Closed(1, 10).Count; // 10
Remarks
DiscreteInterval<T> is the discrete counterpart to the continuous Interval<T>. Where Interval<T> models a continuum of real coordinates, DiscreteInterval<T> models the set of representable integers between its bounds, which changes two behaviours fundamentally:
-
Emptiness reflects representable membership. An open interval whose bounds are consecutive integers - for
example
(1, 2)- contains no integer and is therefore empty, unlike the non-empty continuous interval over the same bounds. -
Adjacency is by successor. Two intervals that leave no integer between them - for example
[1, 2]and[3, 4]- are adjacent and union to a single run[1, 4], because no integer lies in the gap.
Every interval is canonicalized to inclusive [First, Last] integer bounds at construction (an open bound is
shifted inward by one), so all equal integer sets share one representation and the default value is the empty set.
Unbounded and half-bounded intervals ([a, +∞), (-∞, b], (-∞, +∞))
are supported through the AtLeast(T), AtMost(T), and All factory
family.
Domain scope. This type is deliberately integer-only - its domain is IBinaryInteger<TSelf>. It is not a general discrete-domain abstraction: ranges over DateOnly, char, enum values, or a custom successor domain are out of scope. For a disconnected result - the union of several runs - use IntervalSet<T>.
Properties
All
Gets the unbounded interval (-∞, +∞) - every integer of T.
public static DiscreteInterval<T> All { get; }
Property Value
- DiscreteInterval<T>
An interval unbounded on both sides.
Count
Gets the number of integers in the interval.
public T Count { get; }
Property Value
- T
The inclusive count
Last - First + 1, or zero when empty.
Exceptions
- InvalidOperationException
The interval is unbounded, so its count is infinite.
- OverflowException
The count does not fit in
T- a full-domain interval has one more member than the type can represent.
Empty
Gets the canonical empty interval - the interval that contains no integer. Equal to every other empty DiscreteInterval<T> and to the default value.
public static DiscreteInterval<T> Empty { get; }
Property Value
First
Gets the inclusive lower bound. Meaningful only for a non-empty, lower-bounded interval.
public T First { get; }
Property Value
- T
The smallest integer in the interval.
IsBounded
Gets a value indicating whether both sides are bounded by a finite integer.
public bool IsBounded { get; }
Property Value
IsEmpty
Gets a value indicating whether the interval contains no integer.
public bool IsEmpty { get; }
Property Value
Last
Gets the inclusive upper bound. Meaningful only for a non-empty, upper-bounded interval.
public T Last { get; }
Property Value
- T
The largest integer in the interval.
LowerUnbounded
Gets a value indicating whether the lower side is unbounded (extends to -∞).
public bool LowerUnbounded { get; }
Property Value
UpperUnbounded
Gets a value indicating whether the upper side is unbounded (extends to +∞).
public bool UpperUnbounded { get; }
Property Value
Methods
AtLeast(T)
Creates the lower-bounded interval [lower, +∞) - every integer greater than or equal to
lower.
public static DiscreteInterval<T> AtLeast(T lower)
Parameters
lowerTThe inclusive lower bound.
Returns
- DiscreteInterval<T>
An upper-unbounded interval.
AtMost(T)
Creates the upper-bounded interval (-∞, upper] - every integer less than or equal to
upper.
public static DiscreteInterval<T> AtMost(T upper)
Parameters
upperTThe inclusive upper bound.
Returns
- DiscreteInterval<T>
A lower-unbounded interval.
Closed(T, T)
Creates the closed interval [lower, upper] - every integer from lower to
upper inclusive.
public static DiscreteInterval<T> Closed(T lower, T upper)
Parameters
lowerTThe inclusive lower bound.
upperTThe inclusive upper bound.
Returns
- DiscreteInterval<T>
The interval, or Empty when
lowerexceedsupper.
ClosedOpen(T, T)
Creates the closed-open interval [lower, upper) - every integer from lower inclusive
up to but excluding upper.
public static DiscreteInterval<T> ClosedOpen(T lower, T upper)
Parameters
lowerTThe inclusive lower bound.
upperTThe exclusive upper bound.
Returns
- DiscreteInterval<T>
The canonicalized interval.
Contains(T)
Determines whether value is an integer of this interval.
public bool Contains(T value)
Parameters
valueTThe integer to test.
Returns
Difference(DiscreteInterval<T>)
Returns this interval with the integers of other removed - the set difference
this \ other - as zero, one, or two disjoint intervals.
public DiscreteIntervalPair<T> Difference(DiscreteInterval<T> other)
Parameters
otherDiscreteInterval<T>The interval whose integers are removed from this one.
Returns
- DiscreteIntervalPair<T>
The remaining integers as a DiscreteIntervalPair<T>.
Examples
DiscreteInterval<int>.Closed(0, 10).Difference(DiscreteInterval<int>.Closed(3, 5)); // [0, 2] ∪ [6, 10]
Equals(DiscreteInterval<T>)
Determines whether this interval equals other as a set of integers. Because every interval
is canonicalized to a single representation, equal sets compare equal by their stored fields.
public bool Equals(DiscreteInterval<T> other)
Parameters
otherDiscreteInterval<T>The interval to compare against.
Returns
Equals(object?)
Determines whether this interval equals the boxed obj.
public override bool Equals(object? obj)
Parameters
objobjectThe object to compare against.
Returns
- bool
true when
objis an equal DiscreteInterval<T>; otherwise false.
FromInterval(Interval<T>)
Creates the discrete interval containing exactly the integers of interval, snapping open
bounds inward to the nearest contained integer.
public static DiscreteInterval<T> FromInterval(Interval<T> interval)
Parameters
intervalInterval<T>The continuous interval to convert.
Returns
- DiscreteInterval<T>
The discrete interval of the integers within
interval.
GetHashCode()
Returns a hash code consistent with Equals(DiscreteInterval<T>).
public override int GetHashCode()
Returns
- int
A 32-bit hash code.
GreaterThan(T)
Creates the lower-bounded interval (lower, +∞) - every integer greater than
lower.
public static DiscreteInterval<T> GreaterThan(T lower)
Parameters
lowerTThe exclusive lower bound.
Returns
- DiscreteInterval<T>
An upper-unbounded interval, or Empty when
loweris the domain maximum and no integer lies above it.
Intersect(DiscreteInterval<T>)
Returns the intersection of this interval with other - the integers in both.
public DiscreteInterval<T> Intersect(DiscreteInterval<T> other)
Parameters
otherDiscreteInterval<T>The interval to intersect with.
Returns
- DiscreteInterval<T>
The intersection, or Empty when the two share no integer.
LessThan(T)
Creates the upper-bounded interval (-∞, upper) - every integer less than upper.
public static DiscreteInterval<T> LessThan(T upper)
Parameters
upperTThe exclusive upper bound.
Returns
- DiscreteInterval<T>
A lower-unbounded interval, or Empty when
upperis the domain minimum and no integer lies below it.
Open(T, T)
Creates the open interval (lower, upper) - every integer strictly between the bounds. Adjacent integer
bounds (for example (1, 2)) admit no integer and yield Empty.
public static DiscreteInterval<T> Open(T lower, T upper)
Parameters
lowerTThe exclusive lower bound.
upperTThe exclusive upper bound.
Returns
- DiscreteInterval<T>
The canonicalized interval.
OpenClosed(T, T)
Creates the open-closed interval (lower, upper] - every integer above lower up to and
including upper.
public static DiscreteInterval<T> OpenClosed(T lower, T upper)
Parameters
lowerTThe exclusive lower bound.
upperTThe inclusive upper bound.
Returns
- DiscreteInterval<T>
The canonicalized interval.
Overlaps(DiscreteInterval<T>)
Determines whether this interval shares any integer with other.
public bool Overlaps(DiscreteInterval<T> other)
Parameters
otherDiscreteInterval<T>The interval to test for overlap.
Returns
Singleton(T)
Creates the single-integer interval [value, value].
public static DiscreteInterval<T> Singleton(T value)
Parameters
valueTThe single integer the interval contains.
Returns
- DiscreteInterval<T>
A one-element interval.
SymmetricDifference(DiscreteInterval<T>)
Returns the symmetric difference of this interval and other - the integers in exactly one of
the two - as zero, one, or two disjoint intervals.
public DiscreteIntervalPair<T> SymmetricDifference(DiscreteInterval<T> other)
Parameters
otherDiscreteInterval<T>The interval to symmetric-difference with.
Returns
- DiscreteIntervalPair<T>
The integers covered by exactly one operand as a DiscreteIntervalPair<T>.
Examples
DiscreteInterval<int>.Closed(0, 5).SymmetricDifference(DiscreteInterval<int>.Closed(3, 8)); // [0, 2] ∪ [6, 8]
ToInterval()
Returns the continuous Interval<T> covering the same bounds, in canonical closed form.
public Interval<T> ToInterval()
Returns
- Interval<T>
The equivalent continuous interval.
Remarks
The result is a continuous interval over the same integer endpoints; it contains the non-integer coordinates between them as well, so it is a superset of this discrete interval's integer members.
ToString()
Returns the canonical bracket-notation string representation - always closed on a finite side, using the infinity glyphs on an unbounded side, and the empty-set glyph for the empty interval.
public override string ToString()
Returns
- string
"[first, last]"for a bounded interval,"[first, +∞)"/"(-∞, last]"/"(-∞, +∞)"for unbounded shapes, or"∅"when empty.
Remarks
All formatting delegates to the equivalent continuous Interval<T> (via ToInterval()), whose canonical closed form over the same endpoints renders identically.
ToString(string?)
Returns a string representation of this interval using the endpoint format specifier format
applied to First and Last.
public string ToString(string? format)
Parameters
formatstringA format specifier accepted by
T(e.g."D4","N0").
Returns
- string
The interval text with each endpoint formatted by
format.
ToString(string?, IFormatProvider?)
Returns a string representation of this interval using the supplied endpoint format and culture.
public string ToString(string? format, IFormatProvider? formatProvider)
Parameters
formatstringA format specifier accepted by
T.formatProviderIFormatProviderThe culture used to render each endpoint.
Returns
- string
The interval text with each endpoint formatted by
formatunderformatProvider.
TryFormat(Span<byte>, out int, ReadOnlySpan<char>, IFormatProvider?)
Attempts to format this interval into the provided UTF-8 byte span.
public bool TryFormat(Span<byte> utf8Destination, out int bytesWritten, ReadOnlySpan<char> format, IFormatProvider? provider)
Parameters
utf8DestinationSpan<byte>The span that receives the formatted UTF-8 bytes.
bytesWrittenintWhen this method returns, contains the number of bytes written.
formatReadOnlySpan<char>The endpoint format specifier.
providerIFormatProviderThe culture used to render each endpoint.
Returns
TryFormat(Span<char>, out int, ReadOnlySpan<char>, IFormatProvider?)
Attempts to format this interval into the provided character span.
public bool TryFormat(Span<char> destination, out int charsWritten, ReadOnlySpan<char> format, IFormatProvider? provider)
Parameters
destinationSpan<char>The span that receives the formatted characters.
charsWrittenintWhen this method returns, contains the number of characters written.
formatReadOnlySpan<char>The endpoint format specifier.
providerIFormatProviderThe culture used to render each endpoint.
Returns
TryUnion(DiscreteInterval<T>, out DiscreteInterval<T>)
Attempts to compute the union of this interval with other as a single contiguous run of
integers, treating successor-adjacent intervals (no integer between them) as contiguous.
public bool TryUnion(DiscreteInterval<T> other, out DiscreteInterval<T> result)
Parameters
otherDiscreteInterval<T>The interval to union with.
resultDiscreteInterval<T>When this method returns true, the contiguous union; otherwise Empty.
Returns
- bool
true when the two intervals overlap or are successor-adjacent; false when an integer gap separates them so their union needs two runs.
Examples
DiscreteInterval<int>.Closed(1, 2).TryUnion(DiscreteInterval<int>.Closed(3, 4), out var run);
// run == [1, 4], result == true (no integer lies between 2 and 3)
Operators
operator ==(DiscreteInterval<T>, DiscreteInterval<T>)
Determines whether two intervals are equal as sets.
public static bool operator ==(DiscreteInterval<T> left, DiscreteInterval<T> right)
Parameters
leftDiscreteInterval<T>The first interval.
rightDiscreteInterval<T>The second interval.
Returns
operator !=(DiscreteInterval<T>, DiscreteInterval<T>)
Determines whether two intervals are not equal as sets.
public static bool operator !=(DiscreteInterval<T> left, DiscreteInterval<T> right)
Parameters
leftDiscreteInterval<T>The first interval.
rightDiscreteInterval<T>The second interval.
Returns
Applies to
| Product | Versions |
|---|---|
| .NET | 8, 10 |