Skip to content

Instantly share code, notes, and snippets.

@atmoz
Last active July 5, 2018 10:54
Show Gist options
  • Save atmoz/14157ad76a8ac49e092421de565e35f5 to your computer and use it in GitHub Desktop.
Save atmoz/14157ad76a8ac49e092421de565e35f5 to your computer and use it in GitHub Desktop.
package main
import (
"fmt"
"os"
"sort"
"strconv"
"strings"
"github.com/docopt/docopt-go"
)
type Intervals []Interval
type Interval struct {
Min int
Max int
}
func (interval Interval) String() string {
return fmt.Sprintf("%d-%d", interval.Min, interval.Max)
}
func (intervals Intervals) String() string {
var str string
for i, v := range intervals {
str += v.String()
if i < len(intervals)-1 {
str += ", "
}
}
return str
}
func main() {
usage := `Interval - Include and exclude intervals
Usage:
interval [--include=INTERVAL...] [--exclude=INTERVAL...]
interval (-h | --help)
INTERVAL:
Must be in the form: <integer>-<integer>
Example: 10-100`
args, _ := docopt.ParseDoc(usage)
include := intervalsToInts(parseIntervals(args["--include"]))
exclude := intervalsToInts(parseIntervals(args["--exclude"]))
fmt.Println(intsToIntervals(difference(include, exclude)))
}
func parseIntervals(args interface{}) (intervals Intervals) {
for _, v := range args.([]string) {
parts := strings.Split(v, "-")
if len(parts) != 2 {
fmt.Println("Intervals must be in the form <integer>-<integer>")
os.Exit(1)
}
min, err0 := strconv.Atoi(parts[0])
max, err1 := strconv.Atoi(parts[1])
if err0 != nil || err1 != nil || !(min > 0 && max > 0) {
fmt.Println("Intervals can only have positive integers")
os.Exit(1)
}
intervals = append(intervals, Interval{min, max})
}
return
}
func intervalsToInts(intervals Intervals) (ints []int) {
for _, interval := range intervals {
seq := make([]int, interval.Max-interval.Min+1)
for i := range seq {
seq[i] = interval.Min + i
}
ints = append(ints, seq...)
}
sort.Ints(ints)
return
}
func intsToIntervals(a []int) (intervals Intervals) {
var min, prev int
for _, v := range a {
if min == 0 { // First number
min = v
} else if prev != v-1 && prev != v { // Close interval when sequence breaks
intervals = append(intervals, Interval{min, prev})
min = v
}
prev = v
}
// Close the last trailing interval
intervals = append(intervals, Interval{min, prev})
return
}
// Find the difference of set b from set a (a - b)
func difference(a []int, b []int) (c []int) {
if len(b) == 0 {
return a
}
for _, v := range a { // Binary search
i := sort.Search(len(b), func(i int) bool { return b[i] >= v })
if !(i < len(b) && b[i] == v) {
c = append(c, v)
}
}
return c
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment