-
-
Notifications
You must be signed in to change notification settings - Fork 95
/
range.go
167 lines (139 loc) · 3.09 KB
/
range.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
// Copyright 2018-20 PJ Engineering and Business Solutions Pty. Ltd. All rights reserved.
package dataframe
import (
"errors"
"fmt"
)
// Range is used to specify a range. Both Start and End are inclusive.
// A nil value means no limit, so a Start of nil means 0
// and an End of nil means no limit.
// The End value must always be equal to or larger than Start.
// Negative values are acceptable. A value of -2 means the second last row.
type Range struct {
Start *int
End *int
}
// String implements Stringer interface.
func (r Range) String() string {
if r.Start == nil {
if r.End == nil {
return "Range:nil—nil"
}
return fmt.Sprintf("Range:nil—%d", *r.End)
}
if r.End == nil {
return fmt.Sprintf("Range:%d—nil", *r.Start)
}
return fmt.Sprintf("Range:%d—%d", *r.Start, *r.End)
}
// NRows returns the number of rows contained by Range.
// If End is nil, then length must be provided.
func (r *Range) NRows(length ...int) (int, error) {
if len(length) > 0 {
s, e, err := r.Limits(length[0])
if err != nil {
return 0, err
}
return e - s + 1, nil
}
if r.End == nil {
return 0, errors.New("End is nil so length must be provided")
}
var s int
if r.Start != nil {
s = *r.Start
}
if s < 0 || *r.End < 0 {
return 0, errors.New("range invalid")
}
if *r.End < s {
return 0, errors.New("range invalid")
}
return *r.End - s + 1, nil
}
// Limits is used to return the start and end limits of a Range
// object for a given Dataframe or Series with length number of rows.
func (r *Range) Limits(length int) (s int, e int, _ error) {
if length <= 0 {
return 0, 0, errors.New("limit undefined")
}
if r.Start == nil {
s = 0
} else {
if *r.Start < 0 {
// negative
s = length + *r.Start
} else {
s = *r.Start
}
}
if r.End == nil {
e = length - 1
} else {
if *r.End < 0 {
// negative
e = length + *r.End
} else {
e = *r.End
}
}
if s < 0 || e < 0 {
return 0, 0, errors.New("range invalid")
}
if s > e {
return 0, 0, errors.New("range invalid")
}
if s >= length || e >= length {
return 0, 0, errors.New("range invalid")
}
return
}
// RangeFinite returns a Range that has a finite span.
func RangeFinite(start int, end ...int) Range {
r := Range{
Start: &start,
}
if len(end) > 0 {
r.End = &end[0]
}
return r
}
// IntsToRanges will convert an already (ascending) ordered list of ints to a slice of Ranges.
//
// Example:
//
// import "sort"
// ints := []int{2,4,5,6,8,10,11,45,46}
// sort.Ints(ints)
//
// fmt.Println(IntsToRanges(ints))
// // Output: R{2,2}, R{4,6}, R{8,8}, R{10,11}, R{45,46}
//
func IntsToRanges(ints []int) []Range {
out := []Range{}
OUTER:
for i := 0; i < len(ints); i++ {
v1 := ints[i]
j := i + 1
for {
if j >= len(ints) {
// j doesn't exist
v2 := ints[j-1]
out = append(out, Range{Start: &v1, End: &v2})
break OUTER
} else {
// j does exist
v2 := ints[j]
prevVal := ints[j-1]
if (v2 != prevVal) && (v2 != prevVal+1) {
out = append(out, Range{Start: &v1, End: &prevVal})
i = j - 1
break
}
j++
continue
}
}
}
return out
}