splited big file into smaller files by functionality

This commit is contained in:
Daniel Gil 2018-05-25 13:02:52 +02:00
parent 941fe9746a
commit 786bcb162b
10 changed files with 308 additions and 175 deletions

13
add.go Normal file
View File

@ -0,0 +1,13 @@
package interval
func (intvls *intervals) Add(itvl *Interval) {
intvls.Intervals = append(intvls.Intervals, itvl)
intvls.reset()
}
func (intvls *intervals) reset() {
intvls.Sorted = false
intvls.GapsList = nil
intvls.OverlappedList = nil
intvls.MergeList = nil
}

16
find.go Normal file
View File

@ -0,0 +1,16 @@
package 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)
}
}
return matches
}

34
gaps.go Normal file
View File

@ -0,0 +1,34 @@
package interval
func (intvls *intervals) HasGaps() bool {
intvls.Gaps()
if intvls.GapsList != nil && len(intvls.GapsList) > 0 {
return true
}
return false
}
func (intvls *intervals) Gaps() []*Interval {
if intvls.GapsList == nil {
intvls.GapsList = intvls.calculateGaps()
}
return intvls.GapsList
}
func (intvls *intervals) calculateGaps() []*Interval {
intvls.Sort()
gaps := []*Interval{}
lastMaxHigh := intvls.MinLow
for _, intvl := range intvls.Intervals {
if intvl.Low > lastMaxHigh {
gaps = append(gaps, &Interval{Low: lastMaxHigh, High: intvl.Low - 1})
}
if intvl.High >= lastMaxHigh {
lastMaxHigh = intvl.High + 1
}
}
if lastMaxHigh < intvls.MaxHigh {
gaps = append(gaps, &Interval{Low: lastMaxHigh, High: intvls.MaxHigh})
}
return gaps
}

View File

@ -8,6 +8,7 @@ type Interval struct {
Object interface{}
}
// String implements Stringer.Interface Interval
func (itvl Interval) String() string {
return fmt.Sprintf("(%v, %v)", itvl.Low, itvl.High)
}

View File

@ -27,7 +27,7 @@ func TestInsert(t *testing.T) {
for _, tc := range tt {
t.Run(tc.name, func(t *testing.T) {
t.Log(tc.itvls.Print())
t.Log(tc.itvls.Report())
})
}
}

View File

@ -1,9 +1,7 @@
package interval
import (
"fmt"
"math"
"sort"
)
const (
@ -18,25 +16,37 @@ type Intervals interface {
// Sort sorts the intervals list by the Low property (ascending)
Sort()
// HasGaps returns true if exists gaps for the introduced intervals between MinLow and MaxHigh
HasGaps() bool
// Gaps first sorts (if necessary) and then returns the interval gaps
Gaps() []*Interval
// Merge first sorts (if necessary) and then fussion together overlapped intervals
Merge() []*Interval
// HasOverlapped returns true if exists overlapping for the introduced intervals
HasOverlapped() bool
// Overlapped first sorts (if necessary) and then returns the overlapped intervals
Overlapped() []*Interval
// FindIntervalsForValue returns all the intervals which contains the passed value
FindIntervalsForValue(value int) []*Interval
// Print first sorts (if necessary) and then displays graphically the interval sequence
Print() string
// Report first sorts (if necessary) and then creates a report of the interval sequence
Report() string
}
// intervals implements Intervals interface
type intervals struct {
Intervals []*Interval
MinLow int
MaxHigh int
Sorted bool
Intervals []*Interval
GapsList []*Interval
OverlappedList []*Interval
MergeList []*Interval
MinLow int
MaxHigh int
Sorted bool
}
// NewIntervalsDefault is a constructor that returns an instance of the Intervals interface with default values
@ -53,169 +63,3 @@ func NewIntervals(minLow int, maxHigh int) Intervals {
Sorted: false,
}
}
func (intvls *intervals) Add(itvl *Interval) {
intvls.Intervals = append(intvls.Intervals, itvl)
intvls.Sorted = false
}
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)
}
}
return matches
}
func (intvls *intervals) Sort() {
if !intvls.Sorted {
sort.Sort(ByLow(intvls.Intervals))
}
intvls.Sorted = true
}
func (intvls *intervals) Gaps() []*Interval {
intvls.Sort()
gaps := []*Interval{}
lastMaxHigh := intvls.MinLow
for _, intvl := range intvls.Intervals {
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
}
}
if lastMaxHigh < intvls.MaxHigh {
gaps = append(gaps, &Interval{Low: lastMaxHigh, High: intvls.MaxHigh})
}
return gaps
}
func (intvls *intervals) Overlapped() []*Interval {
intvls.Sort()
list := []*Interval{}
lastMinLow := math.MaxInt64
lastMaxHigh := math.MinInt64
for i, intvl := range intvls.Intervals {
if i > 0 {
lowInBetween := inBetweenInclusive(lastMinLow, intvl.Low, intvl.High) || inBetweenInclusive(intvl.Low, lastMinLow, lastMaxHigh)
highInBetween := inBetweenInclusive(lastMaxHigh, intvl.Low, intvl.High) || inBetweenInclusive(intvl.High, lastMinLow, lastMaxHigh)
if lowInBetween || highInBetween {
greaterLow := max(intvl.Low, lastMinLow)
lowerHigh := min(intvl.High, lastMaxHigh)
list = append(list, &Interval{Low: greaterLow, High: lowerHigh})
}
}
if intvl.Low < lastMinLow {
lastMinLow = intvl.Low
}
if intvl.High > lastMaxHigh {
lastMaxHigh = intvl.High
}
}
return list
}
func (intvls *intervals) isOverlapping(value int, overlapped []*Interval) bool {
for _, ovrlp := range overlapped {
if inBetweenInclusive(value, ovrlp.Low, ovrlp.High) {
return true
}
}
return false
}
func (intvls *intervals) Print() string {
intvls.Sort()
// Available Symbols: ( ◯ ◌ ◍ ◎ ● ◉ ) , ( □ ■ ), ( ░ ▒ ▓ █ )
emptySymbol := "◌"
fullSymbol := "◎"
overlapSymbol := "●"
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)
intervalText := "\n • Intervals: "
gapsText := "\n • Gaps: "
overlapText := "\n • Overlapped: "
graph := ""
index := intvls.MinLow
blockSize := 10
numSeparators := 0
overlapped := intvls.Overlapped()
for i, ovrlp := range overlapped {
if i != 0 {
overlapText += ", "
}
overlapText += fmt.Sprintf("[%d,%d]", ovrlp.Low, ovrlp.High)
}
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%blockSize == 0 {
graph += separator
numSeparators++
}
}
for i := index; i <= intvl.High; i++ {
if intvls.isOverlapping(index, overlapped) {
graph += overlapSymbol
} else {
graph += fullSymbol
}
index++
if index%blockSize == 0 {
graph += separator
numSeparators++
}
}
}
gaps := intvls.Gaps()
for i, gap := range gaps {
if i != 0 {
gapsText += ", "
}
gapsText += fmt.Sprintf("[%d,%d]", gap.Low, gap.High)
}
for i := index + 1; i < intvls.MaxHigh; i++ {
graph += emptySymbol
if i%blockSize == 0 {
graph += separator
numSeparators++
}
}
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%s%s", axisLegend, leadingSymbol, graph, trailingSymbol)
return "\n" + introText + legend + intervalText + gapsText + overlapText + graphText + "\n"
}

32
merge.go Normal file
View File

@ -0,0 +1,32 @@
package interval
func (intvls *intervals) Merge() []*Interval {
if intvls.MergeList == nil {
intvls.MergeList = intvls.calculateMerged()
}
return intvls.MergeList
}
func (intvls *intervals) calculateMerged() []*Interval {
intvls.Sort()
list := []*Interval{}
var lastLow int
var lastHigh int
for i, intvl := range intvls.Intervals {
if i == 0 {
lastLow = intvl.Low
lastHigh = intvl.High
continue
}
if inBetweenInclusive(intvl.Low, lastLow, lastHigh) {
// because the intervals are previously sorted, we just need to take care of the High value
if intvl.High > lastHigh {
lastHigh = intvl.High
}
continue
}
list = append(list, &Interval{Low: lastLow, High: lastHigh})
}
list = append(list, &Interval{Low: lastLow, High: lastHigh})
return list
}

52
overlap.go Normal file
View File

@ -0,0 +1,52 @@
package interval
import "math"
func (intvls *intervals) HasOverlapped() bool {
intvls.Overlapped()
if intvls.OverlappedList != nil && len(intvls.OverlappedList) > 0 {
return true
}
return false
}
func (intvls *intervals) Overlapped() []*Interval {
if intvls.OverlappedList == nil {
intvls.OverlappedList = intvls.calculateOverlapped()
}
return intvls.OverlappedList
}
func (intvls *intervals) calculateOverlapped() []*Interval {
intvls.Sort()
list := []*Interval{}
lastMinLow := math.MaxInt64
lastMaxHigh := math.MinInt64
for i, intvl := range intvls.Intervals {
if i > 0 {
lowInBetween := inBetweenInclusive(lastMinLow, intvl.Low, intvl.High) || inBetweenInclusive(intvl.Low, lastMinLow, lastMaxHigh)
highInBetween := inBetweenInclusive(lastMaxHigh, intvl.Low, intvl.High) || inBetweenInclusive(intvl.High, lastMinLow, lastMaxHigh)
if lowInBetween || highInBetween {
greaterLow := max(intvl.Low, lastMinLow)
lowerHigh := min(intvl.High, lastMaxHigh)
list = append(list, &Interval{Low: greaterLow, High: lowerHigh})
}
}
if intvl.Low < lastMinLow {
lastMinLow = intvl.Low
}
if intvl.High > lastMaxHigh {
lastMaxHigh = intvl.High
}
}
return list
}
func (intvls *intervals) isOverlapping(value int, overlapped []*Interval) bool {
for _, ovrlp := range overlapped {
if inBetweenInclusive(value, ovrlp.Low, ovrlp.High) {
return true
}
}
return false
}

131
report.go Normal file
View File

@ -0,0 +1,131 @@
package interval
import "fmt"
var blockSize = 10
type symbols struct {
emptySymbol string
fullSymbol string
overlapSymbol string
leadingSymbol string
trailingSymbol string
separator string
}
func newSymbols() symbols {
// Available Symbols: ( ◯ ◌ ◍ ◎ ● ◉ ) , ( □ ■ ), ( ░ ▒ ▓ █ )
return symbols{
emptySymbol: "◌",
fullSymbol: "◎",
overlapSymbol: "●",
leadingSymbol: "├",
trailingSymbol: "┤",
separator: "|",
}
}
func (intvls *intervals) Report() string {
intvls.Sort()
symbols := newSymbols()
intro := intvls.buildHeading(symbols)
index := intvls.MinLow
numSeparators := 0
overlapText := intvls.reportOverlapped()
intervalText := ""
graph := ""
intervalText, index, graph, numSeparators = intvls.reportIntervals(index, symbols, numSeparators)
gapsText := intvls.reportGaps()
graph, numSeparators, index = intvls.fillUntilTheEnd(index, symbols, graph, numSeparators)
axisLegend := intvls.buildAxisLegend()
graphText := fmt.Sprintf("\n\n%s\n%s%s%s", axisLegend, symbols.leadingSymbol, graph, symbols.trailingSymbol)
return "\n" + intro + intervalText + gapsText + overlapText + graphText + "\n"
}
func (intvls *intervals) buildHeading(symbols symbols) string {
introText := fmt.Sprintf("\n==================================\n REPORT (minLow=%d, maxHigh=%d)\n==================================", intvls.MinLow, intvls.MaxHigh)
legend := fmt.Sprintf("\n • Legend: %v (empty), %v (full), %v (overlap)", symbols.emptySymbol, symbols.fullSymbol, symbols.overlapSymbol)
return introText + legend
}
func (intvls *intervals) reportIntervals(index int, symbols symbols, numSeparators int) (string, int, string, int) {
graph := ""
intervalText := "\n • Intervals: "
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 += symbols.emptySymbol
if index%blockSize == 0 {
graph += symbols.separator
numSeparators++
}
}
for i := index; i <= intvl.High; i++ {
if intvls.isOverlapping(index, intvls.OverlappedList) {
graph += symbols.overlapSymbol
} else {
graph += symbols.fullSymbol
}
index++
if index%blockSize == 0 {
graph += symbols.separator
numSeparators++
}
}
}
return intervalText, index, graph, numSeparators
}
func (intvls *intervals) fillUntilTheEnd(index int, symbols symbols, graph string, numSeparators int) (string, int, int) {
for i := index + 1; i <= intvls.MaxHigh+1; i++ {
graph += symbols.emptySymbol
if i%blockSize == 0 {
graph += symbols.separator
numSeparators++
}
}
return graph, numSeparators, index
}
func (intvls *intervals) reportOverlapped() string {
overlapText := "\n • Overlapped: "
overlapped := intvls.Overlapped()
for i, ovrlp := range overlapped {
if i != 0 {
overlapText += ", "
}
overlapText += fmt.Sprintf("[%d,%d]", ovrlp.Low, ovrlp.High)
}
return overlapText
}
func (intvls *intervals) reportGaps() string {
gapsText := "\n • Gaps: "
gaps := intvls.Gaps()
for i, gap := range gaps {
if i != 0 {
gapsText += ", "
}
gapsText += fmt.Sprintf("[%d,%d]", gap.Low, gap.High)
}
return gapsText
}
func (intvls *intervals) buildAxisLegend() string {
axisLegend := " "
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)
return axisLegend
}

10
sort.go Normal file
View File

@ -0,0 +1,10 @@
package interval
import "sort"
func (intvls *intervals) Sort() {
if !intvls.Sorted {
sort.Sort(ByLow(intvls.Intervals))
}
intvls.Sorted = true
}