Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up

.Net Library that aids in comparison and handling values ranges or time bounded periods.

License

NotificationsYou must be signed in to change notification settings

reynj/reynj

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Build StatusNuGet

What is Reynj?

.Net Library that aids in comparison and handling value ranges or time bounded periods. Other names for a Range are Interval, Sequence, Period, Span, ...

This implementation is based on theRange class as described by Martin Fowler.

The aim of this library is to provide a base Range class with all possible methods that can be performed on a Range, but also extension methods that can be used to handle and compare lists of Ranges.Below is my list of features I want to implement, feel free to open an issue if something is missing on my list.

Click to expand the list
- [ ] Range  - [ ] Boundaries  - [ ] Implicit Index & Range support, see [Adding Index and Range support to existing library types](https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/proposals/csharp-8.0/ranges#adding-index-and-range-support-to-existing-library-types)  - [ ] Type of Range should IComparable or IComparable<T>   - [x] Implements    - [x] IEquatable    - [x] IComparable    - [x] ICloneable    - [ ] IEnumerable ??  - [x] Operators     - [x] Equals     - [x] CompareTo     - [x] Convert to/from Tuple  - [ ] Methods    - [x] IsNullOrEmpty    - [x] Includes & IncludesAll    - [x] Overlaps    - [x] Touches    - [x] Gap    - [x] Merge (Union)    - [x] Split    - [x] Intersection    - [x] Exclusive    - [ ] EnumerateBy       - [x] Ascending (protected)       - [ ] Descending (protected)       - [ ] EnumerateBy without stepper function (via dynamic or Expressions) (public)    - [ ] Expand (change the end)    - [ ] Move (change the start and keep the gap between the end the same)    - [ ] CenterValue (get the value in the middle between start and end)  - [ ] Specific implemenations     - [ ] DateRange or Period       - [ ] EnumerateBy    - [ ] TimeRange       - [ ] EnumerateBy    - [ ] NumericRange       - [ ] EnumerateBy- [ ] Collection of Ranges  - [ ] Methods    - [x] Lowest/Highest    - [x] IsContiguous    - [ ] ToRange (only possible for a Contiguous collection)    - [x] IsSingle    - [x] Reduce    - [x] Sort    - [x] Union    - [x] Intersect    - [x] Inverse    - [ ] Difference (Relative complement)    - [ ] Exclusive    - [ ] Enumerate (call EnumerateBy on all ranges)    - [ ] ContainsOverlaps (if ranges in the collection overlap)- [ ] Serialize/Deserialize  - [x] SerializableAttribute   - [x] JsonConvertor (System.Text.Json)  - [x] JsonConvertor (Newtonsoft Json.NET)  - [ ] Entity Framework ValueConvertor  - [ ] NHibernate IUserType- [x] Other  - [x] Range<T>.Empty and methods like Merge, Overlaps, Touches, ...  - [x] IsEmpty method vs Range<T>.Empty  - [x] Support for conversion between System.Range (C# 8.0) and Range<int>

Where can I get it?

First,install NuGet. Then, installReynj from the package manager console:

PM> Install-Package Reynj

How to use it?

What is a Range?

A Range is best visualized as a bar. It has a start and an end and contains everything between those two. Below is a visualization of Range of integers that start at 0 and end at 10. All whole numbers between 0 and 10 are included in the Range, except 10.

gantt    dateFormat  YYYY-MM-DD.HH    axisFormat %-H    title Range<int>        Range[0,10]           : 2018-01-01.00, 10h
Loading

To create this Range in code, you can do the following:

varrange=newRange<int>(0,10);

There is only one limitation, the start of Range must be lower or equal to the end.

What are the types of Ranges that can be created?

The type of Range must derive from theIComparable interface. Below some common examples.

// Numeric RangesvarintRange=newRange<int>(0,10);vardoubleRange=newRange<double>(0.0,0.5);// Date and Time RangesvardateRange=newRange<DateTime>(newDateTime(2018,12,18),newDateTime(2018,12,25));// PeriodvartimeSpanRange=newRange<TimeSpan>(TimeSpan.FromHours(0),TimeSpan.FromHours(6));// Duration

What is an Empty Range?

Every Range where start and end are equal.

varrange1=newRange<int>(10,10);varrange2=newRange<int>(0,0);varrange3=Range<int>.Empty;// Emptyvarequals=range1.Equals(range2);// returns truevarequals=range2.Equals(range3);// returns truevarcompare=range1.CompareTo(range3);// returns 0

What can be done with a Range?

Determining equality

Because Range implements theIEquatable interface, including the operators the following can be done:

varrange1=newRange<int>(0,10);varrange2=newRange<int>(0,10);varrange3=newRange<int>(5,9);// Equalsvarres1=range1.Equals(range2);// returns truevarres2=range1.Equals(range3);// returns false// Equality Operatorsvarres3=range1==range2;// returns truevarres4=range1!=range2;// returns falsevarres5=range1==range3;// returns falsevarres6=range1!=range3;// returns true
Ordering or Sorting

Because Range implements theIComparable interface, including the operators the following can be done:

varrange1=newRange<int>(0,10);varrange2=newRange<int>(5,9);// CompareTovarres1=range1.CompareTo(range2);// returns -1// Equality Operatorsvarres2=range1<range2;// returns truevarres3=range1>range2;// returns falsevarres4=range1<=range2;// returns truevarres5=range1>=range2;// returns false
Tuples

A Range has two primary properties, Start and End, because of that a Range can also be represented as a Tuple, in the lastest versions of .Net as aValueTuple.The constructor of a Range accepts a Tuple of two elements and there is an AsTuple method to convert a Range to a ValueTuple<T, T>.Conversion operators have been implemented to make this even more smoothly.

vartuple=(0,10);varrange=newRange<int>(tuple);// AsTuplevarotherTuple=range.AsTuple();// Conversion OperatorsvarotherTuple2=range;// implicit from Range to TuplevarotherRange=(Range<int>)tuple;// explicit from Tuple to Range
Methods
Includes(T value), Includes(Range range) and IncludesAll(IEnumerable values)

Includes will return true if the given value is a part of the Range, otherwise false.IncludesAll will return true if all of the given values are part of the Range, otherwise false.

varrange=newRange<int>(0,10);// Includes(T value)varres1=range1.Includes(5);// returns truevarres2=range1.Includes(20);// returns false// Includes(Range<T> range)varres1=range1.Includes(newRange<int>(2,7));// returns truevarres2=range1.Includes(newRange<int>(20,30));// returns false// IncludesAllvarres3=range1.IncludesAll(0,1,2,3,4,5,6,7,8,9);// returns truevarres4=range1.IncludesAll(0,1,2,3,4,20,6,7,8,9);// returns false
Overlaps(Range range)

Overlaps will return true if two Ranges overlap. The following example are two overlapping ranges.

gantt    dateFormat  YYYY-MM-DD.HH    axisFormat %-H    title Overlaps        Range[0,10]           : 2018-01-01.00, 10h    Range[5,15]           : active, 2018-01-01.05, 10h
Loading
varrange1=newRange<int>(0,10);varrange2=newRange<int>(5,15);varrange3=newRange<int>(15,25);// Overlapsvarres1=range1.Overlaps(range2);// returns truevarres2=range2.Overlaps(range1);// returns truevarres3=range1.Overlaps(range3);// returns false
Touches(Range range)

Touches will return true if two Ranges touch each other. The following example are two touching ranges.

gantt    dateFormat  YYYY-MM-DD.HH    axisFormat %-H    title Touches        Range[0,5]        : 2018-01-01.00, 5h    Range[5,10]       : 2018-01-01.05, 5h
Loading
varrange1=newRange<int>(0,10);varrange2=newRange<int>(10,20);varrange3=newRange<int>(11,20);// Overlapsvarres1=range1.Touches(range2);// returns truevarres2=range2.Touches(range1);// returns truevarres3=range1.Touches(range3);// returns false
Gap(Range range)

Gap returns a new Range that represents the gap between two Ranges.

gantt    dateFormat  YYYY-MM-DD.HH    axisFormat %-H    title Gap        section Ranges    Range[0,5]         : 2018-01-01.00, 5h    Range[10,15]       : 2018-01-01.10, 5h    section Gap    Range[5,10]        : active, 2018-01-01.05, 5h
Loading
varrange1=newRange<int>(0,10);varrange2=newRange<int>(15,20);// Gapvargap1=range1.Gap(range2);// returns new Range<int>(5, 10)vargap2=range2.Gap(range1);// returns new Range<int>(5, 10)
Merge(Range range)

Merge returns a new Range that represents the combined/merged Range, aLogical disjunction.An exception is thrown when the ranges do not overlap or touch each other.

gantt    dateFormat  YYYY-MM-DD.HH    axisFormat %-H    title Merge        section Ranges    Range[0,5]          : 2018-01-01.00, 5h    Range[5,20]         : 2018-01-01.05, 15h    section Merge    Range[0,20]         : active, 2018-01-01.00, 20h
Loading
varrange1=newRange<int>(0,10);varrange2=newRange<int>(5,20);// Mergevarmerge1=range1.Merge(range2);// returns new Range<int>(0, 20)varmerge2=range1|range2;// returns new Range<int>(0, 20)
Split(Range range)

Split returns a Tuple of two Ranges that have been split on the given value.An exception is thrown when the value is not included in the Range.

gantt    dateFormat  YYYY-MM-DD.HH    axisFormat %-H    title Split        section Range    Range[0,10]          : 2018-01-01.00, 10h        section Split    Range[0,5]           : active, 2018-01-01.00, 5h    Range[5,10]          : active, 2018-01-01.05, 5h
Loading
varrange=newRange<int>(0,10);// Splitvarsplit=range.Split(5);// returns (new Range<int>(0, 5), new Range<int>(5, 10))
Intersection(Range range)

Intersection returns a new Range that represents the intersection between the current Range and a given Range, aLogical conjunction.An exception is thrown when the ranges do not overlap each other.

gantt    dateFormat  YYYY-MM-DD.HH    axisFormat %-H    title Intersection        section Ranges    Range[0,10]         : 2018-01-01.00, 10h    Range[5,20]         : 2018-01-01.05, 15h    section Intersection    Range[5,10]         : active, 2018-01-01.05, 5h
Loading
varrange1=newRange<int>(0,10);varrange2=newRange<int>(5,20);// Intersectionvarintersection1=range1.Intersection(range2);// returns new Range<int>(5, 10)varintersection2=range1&range2;// returns new Range<int>(5, 10)
Exclusive(Range range)

Exclusive returns a tuple of Ranges that that represent the parts they do not have in common, anExclusive or.An exception is thrown when the ranges are null or Empty.

gantt    dateFormat  YYYY-MM-DD.HH    axisFormat %-H    title Exclusive        section Ranges    Range[0,10]         : 2018-01-01.00, 10h    Range[5,20]         : 2018-01-01.05, 15h    section Exclusive    Range[0, 5]         : active, 2018-01-01.00, 5h    Range[10, 20]       : active, 2018-01-01.10, 10h
Loading
varrange1=newRange<int>(0,10);varrange2=newRange<int>(5,20);// Exclusivevarexclusive=range1.Exlusive(range2);// returns (new Range<int>(0, 5), new Range<int>(10, 20))
IsEmpty()

IsEmpty will return true if the start and the end of the Range are equal, otherwise false.

varrange1=newRange<int>(0,10);varrange2=newRange<int>(10,10);// IsEmptyvarres1=range1.IsEmpty();// returns falsevarres2=range2.IsEmpty();// returns true
EnumerateBy(T step, Func<T, T, T> stepper) & EnumerateBy(TStep step, Func<T, TStep, T> stepper)

EnumerateBy returns all values between start and end of the Range, given a step and stepper function.The stepper function should always return a value higher than the previous call. There is an overload that allows the step to be of a different type than the typeof start and end of the Range.This function is protected and should be used in class that inherits from Range.

// EnumerateBy(T step, Func<T, T, T> stepper)varrange=newRange<int>(0,10);varvalues=range.EnumerateBy(2,(value,step)=>value+step);// returns 0, 2, 4, 6, 8// EnumerateBy(TStep step, Func<T, TStep, T> stepper)varstartDate=newDateTimeOffset(2020,8,1,8,0,0,TimeSpan.FromHours(2));varendDate=newDateTimeOffset(2020,8,1,14,0,0,TimeSpan.FromHours(2));varrange=newRange<DateTimeOffset>(startDate,endDate);varvalues=range.EnumerateBy(TimeSpan.FromHours(2),(value,step)=>value.Add(step));// returns 2020-08-01 08:00, 2020-08-01 10:00, 2020-08-01 12:00
Extension Methods
ToRange()

With the ToRange extension methods on both Range and System.Range a conversion can be done between them.A System.Range and a Reynj.Range have not so much in common, aSystem.Range is meant for accessing single elements or ranges in a sequence,but by converting from them to a Range it is possible to use all methods on Range and Enumerable<Range>.

varrange=newRange<int>(0,10);// ToRange()varsysRange=range.ToRange();// returns new System.Range(0, 10)// ToRange()varreynjRange=sysRange.ToRange();// returns new Range<int>(0, 10)
Additional Libraries
Reynj.Text.Json

Provides a converter, namedRangeConverter for the System.Text.Json library.Be aware that the type of Start and End also require a converter, either included in the System.Text.Json library or from another source.

varoptions=newJsonSerializerOptions{Converters={newRangeConverter()}};// Required// Json Serializevarrange=newRange<int>(0,10);varjsonText=JsonSerializer.Serialize(range,options);// returns '{"Start":0,"End":10}'// Json DeserializevarjsonRange=JsonSerializer.Deserialize(jsonRange,range.GetType(),options);// returns new Range<int>(0, 10)

In your ASP.NET project you can add the following code to the Startup.cs to register the converter.

services.AddControllers().AddJsonOptions(options=>{options.JsonSerializerOptions.Converters.Add(newRangeConverter());// ...});
Reynj.Newtonsoft.Json

Provides a converter, namedRangeConverter for the Newtonsoft.Json library.Be aware that the type of Start and End also require a converter, either included in the Newtonsoft.Json library or from another source.

varsettings=newJsonSerializerSettings{Converters={newRangeConverter()}};// Required// Json Serializevarrange=newRange<int>(0,10);varjsonText=JsonConvert.SerializeObject(range,settings);// returns '{"Start":0,"End":10}'// Json DeserializevarjsonRange=JsonConvert.DeserializeObject(json,typeOfRange,settings);// returns new Range<int>(0, 10)

In your ASP.NET project you can add the following code to the Startup.cs to register the converter.

services.AddControllers().AddNewtonsoftJson(options=>{options.SerializerSettings.Converters.Add(newRangeConverter());// ...});

What is a Collection of Ranges?

A Collection of Ranges is a group or list of Ranges of the same type.

gantt    dateFormat  YYYY-MM-DD.HH    axisFormat %-H    title RangeCollection        section Ranges    Range[0,5]         : 2018-01-01.00, 5h    Range[7,10]        : 2018-01-01.07, 3h    Range[10,15]       : 2018-01-01.10, 5h    Range[18,25]       : 2018-01-01.18, 7h
Loading

To create an IEnumerable<Range> in code, you can do the following:

// Collection based on an IEnumerable<Range<T>>varranges=newList<Range<int>>(){newRange<int>(0,10),newRange<int>(10,20)}

What can be done with a Collection of Ranges?

Extension Methods
Lowest() / Highest()

They return the lowest start or highest end of the all the Ranges in the collection.

varranges=newList<Range<int>>{newRange<int>(0,10),newRange<int>(10,20)};// Lowestvarlowest=ranges.Lowest();// returns 0// Highestvarhighest=ranges.Highest();// returns 20
Reduce()

Returns a new Collection of Ranges where all overlapping and touching Ranges have been merged and empty Ranges have been removed.

gantt    dateFormat  YYYY-MM-DD.HH    axisFormat %-H    title Reduce        section Ranges    Range[0,5]         : 2018-01-01.00, 5h    Range[3,10]        : 2018-01-01.03, 7h    Range[10,15]       : 2018-01-01.10, 5h    Range[18,25]       : 2018-01-01.18, 7h    section Reduced    Range[0,15]        : active, 2018-01-01.00, 15h    Range[18,25]       : active, 2018-01-01.18, 7h
Loading
varranges=new[]{newRange<int>(0,5),newRange<int>(3,10),newRange<int>(10,15),newRange<int>(18,25)});// Reducevarreduced=ranges.Reduce();// returns new[] { new Range<int>(0, 15), new Range<int>(18, 25) }
Union()

Returns theunion of two Collections of Ranges while reducing them.An exception is thrown when one or both of the ranges are null.

gantt    dateFormat  YYYY-MM-DD.HH    axisFormat %-H    title Union        section Ranges 1    Range[0,5]         : 2018-01-01.00, 5h    Range[3,10]        : 2018-01-01.03, 7h    Range[10,15]       : 2018-01-01.10, 5h    section Ranges 2    Range[15,17]       : 2018-01-01.15, 2h    Range[18,25]       : 2018-01-01.18, 7h    section Unioned    Range[0,17]        : active, 2018-01-01.00, 17h    Range[18,25]       : active, 2018-01-01.18, 7h
Loading
varranges1=new[]{newRange<int>(0,5),newRange<int>(3,10),newRange<int>(10,15)});varranges2=new[]{newRange<int>(15,17),newRange<int>(18,25)});// Unionvarunioned=ranges1.Union(ranges2);// returns new[] { new Range<int>(0, 17), new Range<int>(18, 25) }
Intersect()

Returns theintersection of two Collections of Ranges while reducing them.An exception is thrown when one or both of the ranges are null.

gantt    dateFormat  YYYY-MM-DD.HH    axisFormat %-H    title Intersect        section Ranges 1    Range[0,5]           : 2018-01-01.00, 5h    Range[3,10]          : 2018-01-01.03, 7h    Range[10,15]         : 2018-01-01.10, 5h    Range[18,20]         : 2018-01-01.18, 2h    section Ranges 2    Range[1,8]           : 2018-01-01.01, 7h    Range[12,25]         : 2018-01-01.12, 13h    section Intersection    Range[1,8]           : active, 2018-01-01.01, 7h    Range[12,15]         : active, 2018-01-01.12, 3h    Range[18,20]         : active, 2018-01-01.18, 2h
Loading
varranges1=new[]{newRange<int>(0,5),newRange<int>(3,10),newRange<int>(10,15),newRange<int>(18,20)});varranges2=new[]{newRange<int>(1,8),newRange<int>(12,25)});// Intersectvarintersection=ranges1.Intersect(ranges2);// returns new[] { new Range<int>(1, 8), new Range<int>(12, 15), new Range<int>(18, 20) }
Inverse()

Returns a new Collection of Ranges that is the inversion of the Ranges. Meaning all gaps between the ranges are returned including the gap between the minvalue and the first start and the last end and the maxvalue.Also known as theabsolute complement.An exception is thrown when the type of Range has no MinValue and MaxValue or when they are not passed.

gantt    dateFormat  YYYY-MM-DD.HH    axisFormat %-H    title Inverse        section Ranges    Range[0,5]           : 2018-01-01.00, 5h    Range[10,15]         : 2018-01-01.10, 5h    Range[18,20]         : 2018-01-01.18, 2h    section Inversion    Range[-∞, 0]         : active, 2017-12-31.21, 3h    Range[5,10]          : active, 2018-01-01.05, 5h    Range[15,28]         : active, 2018-01-01.15, 3h    Range[20,+∞]         : active, 2018-01-01.20, 3h
Loading
varranges=new[]{newRange<int>(0,5),newRange<int>(10,15),newRange<int>(18,20)});// Inversevarinversion=ranges.Inverse();// returns new[] { new Range<int>(int.MinValue, 0), new Range<int>(5, 10), new Range<int>(15, 18), new Range<int>(20, int.MaxValue) }
IsContiguous()

Check if a collection of Ranges only contains touching Ranges and form a contiguous sequence.

gantt    dateFormat  YYYY-MM-DD.HH    axisFormat %-H    title IsContiguous        section Is Contiguous    Range[3,10]          : 2018-01-01.03, 7h    Range[10,15]         : 2018-01-01.10, 5h    section Is Contiguous (overlap)    Range[0, 5]          : crit, done, 2018-01-01.00, 5h    Range[3,10]          : crit, done, 2018-01-01.03, 7h    Range[10,15]         : active, 2018-01-01.10, 5h    section Is Contiguous (gap)    Range[3,10]          : active, done, 2018-01-01.03, 7h    Range[10,15]         : crit, done, 2018-01-01.10, 5h    Range[18,25]         : crit, done, 2018-01-01.18, 7h
Loading
varcontiguousRanges=new[]{newRange<int>(10,15),newRange<int>(18,25)});varwithOverlapRanges=new[]{newRange<int>(0,5),newRange<int>(3,10),newRange<int>(10,15)});varnotTouchingRanges=new[]{newRange<int>(3,10),newRange<int>(10,15),newRange<int>(18,25)});// IsContiguousvarisContiguous1=contiguousRanges.IsContiguous();// returns truevarisContiguous2=withOverlapRanges.IsContiguous();// returns falsevarisContiguous3=notTouchingRanges.IsContiguous();// returns false
IsSingle()

Helper method on IEnumerable that returns true if the sequence contains exacly one element.

varemptyList=newList<Range<int>>();varsingleItemList=new[]{newRange<int>(0,5)});varmultiItemList=new[]{newRange<int>(3,10),newRange<int>(10,15)});// IsSinglevarisSingle1=emptyList.IsSingle();// returns falsevarisSingle2=singleItemList.IsSingle();// returns truevarisSingle3=multiItemList.IsSingle();// returns false

About

.Net Library that aids in comparison and handling values ranges or time bounded periods.

Topics

Resources

License

Code of conduct

Stars

Watchers

Forks

Sponsor this project

 

Languages


[8]ページ先頭

©2009-2025 Movatter.jp