From 941fe9746ab40d23c469ad2b46bf5d24924df253 Mon Sep 17 00:00:00 2001 From: Daniel Gil Date: Thu, 24 May 2018 18:45:37 +0200 Subject: [PATCH] fixed gaps calculations --- interval.go | 7 +++++++ intervals.go | 59 ++++++++++++++++++++++++++++++++++++---------------- 2 files changed, 48 insertions(+), 18 deletions(-) diff --git a/interval.go b/interval.go index 37515e8..640d460 100644 --- a/interval.go +++ b/interval.go @@ -18,3 +18,10 @@ type ByLow []*Interval func (itvls ByLow) Len() int { return len(itvls) } func (itvls ByLow) Swap(i, j int) { itvls[i], itvls[j] = itvls[j], itvls[i] } func (itvls ByLow) Less(i, j int) bool { return itvls[i].Low < itvls[j].Low } + +// ByHigh implements sort.Interface for []Interval based on the High field. +type ByHigh []*Interval + +func (itvls ByHigh) Len() int { return len(itvls) } +func (itvls ByHigh) Swap(i, j int) { itvls[i], itvls[j] = itvls[j], itvls[i] } +func (itvls ByHigh) Less(i, j int) bool { return itvls[i].High > itvls[j].High } diff --git a/intervals.go b/intervals.go index 0270aaf..632b5ce 100644 --- a/intervals.go +++ b/intervals.go @@ -11,8 +11,8 @@ const ( defaultMaxHigh = math.MaxInt64 ) +// Intervals is an interface to handle Interval structures discovering the existence of gaps or overlays type Intervals interface { - // Add appends a new interval Add(itvl *Interval) // Sort sorts the intervals list by the Low property (ascending) @@ -31,6 +31,7 @@ type Intervals interface { Print() string } +// intervals implements Intervals interface type intervals struct { Intervals []*Interval MinLow int @@ -38,10 +39,12 @@ type intervals struct { Sorted bool } +// NewIntervalsDefault is a constructor that returns an instance of the Intervals interface with default values func NewIntervalsDefault() Intervals { return NewIntervals(defaultMinLow, defaultMaxHigh) } +// NewIntervals is a constructor that returns an instance of the Intervals interface func NewIntervals(minLow int, maxHigh int) Intervals { return &intervals{ MinLow: minLow, @@ -57,8 +60,13 @@ func (intvls *intervals) Add(itvl *Interval) { } func (intvls *intervals) FindIntervalsForValue(value int) []*Interval { + intvls.Sort() var matches []*Interval for _, intvl := range intvls.Intervals { + if intvl.Low > value { + // due to the intervals are sorted, we can confirm that we will not find more matches + break + } if inBetweenInclusive(value, intvl.Low, intvl.High) { matches = append(matches, intvl) } @@ -76,15 +84,18 @@ func (intvls *intervals) Sort() { func (intvls *intervals) Gaps() []*Interval { intvls.Sort() gaps := []*Interval{} - lastHigh := intvls.MinLow + lastMaxHigh := intvls.MinLow for _, intvl := range intvls.Intervals { - if intvl.Low > lastHigh { - gaps = append(gaps, &Interval{Low: lastHigh, High: intvl.Low - 1}) + if intvl.Low > lastMaxHigh { + gaps = append(gaps, &Interval{Low: lastMaxHigh, High: intvl.Low - 1}) + } + // lastHigh = intvl.High + 1 + if intvl.High >= lastMaxHigh { + lastMaxHigh = intvl.High + 1 } - lastHigh = intvl.High + 1 } - if lastHigh < intvls.MaxHigh { - gaps = append(gaps, &Interval{Low: lastHigh, High: intvls.MaxHigh}) + if lastMaxHigh < intvls.MaxHigh { + gaps = append(gaps, &Interval{Low: lastMaxHigh, High: intvls.MaxHigh}) } return gaps } @@ -114,7 +125,7 @@ func (intvls *intervals) Overlapped() []*Interval { return list } -func (intvls *intervals) isAnOverlap(value int, overlapped []*Interval) bool { +func (intvls *intervals) isOverlapping(value int, overlapped []*Interval) bool { for _, ovrlp := range overlapped { if inBetweenInclusive(value, ovrlp.Low, ovrlp.High) { return true @@ -130,7 +141,9 @@ func (intvls *intervals) Print() string { emptySymbol := "◌" fullSymbol := "◎" overlapSymbol := "●" - separator := "║" + leadingSymbol := "├" + trailingSymbol := "┤" + separator := "|" introText := fmt.Sprintf("\n==================================\n SUMMARY (minLow=%d, maxHigh=%d)\n==================================", intvls.MinLow, intvls.MaxHigh) legend := fmt.Sprintf("\n • Legend: %v (empty), %v (full), %v (overlap)", emptySymbol, fullSymbol, overlapSymbol) @@ -150,22 +163,22 @@ func (intvls *intervals) Print() string { overlapText += fmt.Sprintf("[%d,%d]", ovrlp.Low, ovrlp.High) } - for i, intvl := range intvls.Intervals { - if i != 0 { + for j, intvl := range intvls.Intervals { + if j != 0 { intervalText += ", " } intervalText += fmt.Sprintf("[%d,%d]", intvl.Low, intvl.High) for i := index; i < intvl.Low; i++ { index++ graph += emptySymbol - if index%10 == 0 { + if index%blockSize == 0 { graph += separator numSeparators++ } } for i := index; i <= intvl.High; i++ { - if intvls.isAnOverlap(index, overlapped) { + if intvls.isOverlapping(index, overlapped) { graph += overlapSymbol } else { graph += fullSymbol @@ -185,14 +198,24 @@ func (intvls *intervals) Print() string { gapsText += fmt.Sprintf("[%d,%d]", gap.Low, gap.High) } - for i := index; i < intvls.MaxHigh; i++ { + for i := index + 1; i < intvls.MaxHigh; i++ { graph += emptySymbol + if i%blockSize == 0 { + graph += separator + numSeparators++ + } } - axisLegend := fmt.Sprintf(" %v", intvls.MinLow) - for i := intvls.MinLow; i < intvls.MaxHigh+numSeparators-2; i++ { - axisLegend += " " + axisLegend := " " + numSeparators = 0 + for i := intvls.MinLow; i < intvls.MaxHigh/blockSize; i++ { + mark := fmt.Sprintf("%d", i*blockSize) + axisLegend += mark + limit := (blockSize - len(mark)) + 1 + for j := 0; j < limit; j++ { + axisLegend += " " + } } axisLegend += fmt.Sprintf("%v", intvls.MaxHigh) - graphText := fmt.Sprintf("\n\n%s\n╠%s╣", axisLegend, graph) + graphText := fmt.Sprintf("\n\n%s\n%s%s%s", axisLegend, leadingSymbol, graph, trailingSymbol) return "\n" + introText + legend + intervalText + gapsText + overlapText + graphText + "\n" }