Last active
July 5, 2018 10:54
-
-
Save atmoz/14157ad76a8ac49e092421de565e35f5 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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