From a4ef258d4d2562b5115efa68a6b149a6fb2659b7 Mon Sep 17 00:00:00 2001 From: Thad Craft Date: Tue, 8 Oct 2019 14:12:01 -0400 Subject: [PATCH 1/2] Add seq function for generating a sequence of numbers --- functions.go | 1 + numeric.go | 29 +++++++++++++++++++++++++++++ numeric_test.go | 16 ++++++++++++++++ 3 files changed, 46 insertions(+) diff --git a/functions.go b/functions.go index 180877a8..8d3542ae 100644 --- a/functions.go +++ b/functions.go @@ -162,6 +162,7 @@ var genericMap = map[string]interface{}{ "int64": toInt64, "int": toInt, "float64": toFloat64, + "seq": seq, "toDecimal": toDecimal, //"gt": func(a, b int) bool {return a > b}, diff --git a/numeric.go b/numeric.go index 49f8419b..58cd82d1 100644 --- a/numeric.go +++ b/numeric.go @@ -4,6 +4,7 @@ import ( "fmt" "math" "strconv" + "strings" "github.com/spf13/cast" ) @@ -112,3 +113,31 @@ func toDecimal(v interface{}) int64 { } return result } + +func seq(params ...int) string { + switch len(params) { + case 0: + return "0" + case 1: + return buildSeq(0, 1, params[0]) + case 3: + return buildSeq(params[0], params[1], params[2]) + case 2: + fallthrough + default: + return strconv.Itoa(params[0]) + } +} + +func buildSeq(start, step, end int) string { + var sequence []string + if start > end { + return strconv.Itoa(start) + } + current := start + for current <= end { + sequence = append(sequence, strconv.Itoa(current)) + current += step + } + return strings.Join(sequence, " ") +} diff --git a/numeric_test.go b/numeric_test.go index b1de8134..dead0973 100644 --- a/numeric_test.go +++ b/numeric_test.go @@ -219,3 +219,19 @@ func TestRound(t *testing.T) { assert.Equal(t, 123.23, round(123.2329999, 2, .3)) assert.Equal(t, 123.24, round(123.233, 2, .3)) } + +func TestSeq(t *testing.T) { + tests := map[string]string{ + `{{seq 0 1 3}}`: "0 1 2 3", + `{{seq 0 3 10}}`: "0 3 6 9", + `{{seq 3 3 2}}`: "3", + `{{seq}}`: "0", + `{{seq 0 1}}`: "0", + `{{seq 10}}`: "0 1 2 3 4 5 6 7 8 9 10", + } + for tpl, expect := range tests { + if err := runt(tpl, expect); err != nil { + t.Error(err) + } + } +} From ad231b89fd6cddb58750c00cc8d690ab917056bc Mon Sep 17 00:00:00 2001 From: Thad Craft Date: Tue, 8 Oct 2019 15:18:25 -0400 Subject: [PATCH 2/2] Use untilStep to build the seq command response --- docs/integer_slice.md | 16 ++++++++++++++++ numeric.go | 44 +++++++++++++++++++++++++++---------------- numeric_test.go | 17 +++++++++++------ 3 files changed, 55 insertions(+), 22 deletions(-) diff --git a/docs/integer_slice.md b/docs/integer_slice.md index 8929d303..b4423b45 100644 --- a/docs/integer_slice.md +++ b/docs/integer_slice.md @@ -23,3 +23,19 @@ untilStep 3 6 2 The above will produce `[3 5]` by starting with 3, and adding 2 until it is equal or greater than 6. This is similar to Python's `range` function. + +## seq + +Works like the bash `seq` command. +* 1 parameter (end) - will generate all counting integers between 1 and `end` inclusive. +* 2 parameters (start, end) - will generate all counting integers between `start` and `end` inclusive incrementing or decrementing by 1. +* 3 parameters (start, step, end) - will generate all counting integers between `start` and `end` inclusive incrementing or decrementing by `step`. + +``` +seq 5 => 0 1 2 3 4 5 +seq -3 => 1 0 -1 -2 -3 +seq 0 2 => 0 1 2 +seq 2 -2 => 2 1 0 -1 -2 +seq 0 2 10 => 0 2 4 6 8 10 +seq 0 -2 -5 => 0 -2 -4 +``` diff --git a/numeric.go b/numeric.go index 58cd82d1..638ef273 100644 --- a/numeric.go +++ b/numeric.go @@ -115,29 +115,41 @@ func toDecimal(v interface{}) int64 { } func seq(params ...int) string { + increment := 1 switch len(params) { case 0: - return "0" + return "" case 1: - return buildSeq(0, 1, params[0]) + start := 1 + end := params[0] + if end < start { + increment = -1 + } + return intArrayToString(untilStep(start, end+increment, increment), " ") case 3: - return buildSeq(params[0], params[1], params[2]) + start := params[0] + end := params[2] + step := params[1] + if end < start { + increment = -1 + if step > 0 { + return "" + } + } + return intArrayToString(untilStep(start, end+increment, step), " ") case 2: - fallthrough + start := params[0] + end := params[1] + step := 1 + if end < start { + step = -1 + } + return intArrayToString(untilStep(start, end+step, step), " ") default: - return strconv.Itoa(params[0]) + return "" } } -func buildSeq(start, step, end int) string { - var sequence []string - if start > end { - return strconv.Itoa(start) - } - current := start - for current <= end { - sequence = append(sequence, strconv.Itoa(current)) - current += step - } - return strings.Join(sequence, " ") +func intArrayToString(slice []int, delimeter string) string { + return strings.Trim(strings.Join(strings.Fields(fmt.Sprint(slice)), delimeter), "[]") } diff --git a/numeric_test.go b/numeric_test.go index dead0973..034707c5 100644 --- a/numeric_test.go +++ b/numeric_test.go @@ -222,12 +222,17 @@ func TestRound(t *testing.T) { func TestSeq(t *testing.T) { tests := map[string]string{ - `{{seq 0 1 3}}`: "0 1 2 3", - `{{seq 0 3 10}}`: "0 3 6 9", - `{{seq 3 3 2}}`: "3", - `{{seq}}`: "0", - `{{seq 0 1}}`: "0", - `{{seq 10}}`: "0 1 2 3 4 5 6 7 8 9 10", + `{{seq 0 1 3}}`: "0 1 2 3", + `{{seq 0 3 10}}`: "0 3 6 9", + `{{seq 3 3 2}}`: "", + `{{seq 3 -3 2}}`: "3", + `{{seq}}`: "", + `{{seq 0 4}}`: "0 1 2 3 4", + `{{seq 5}}`: "1 2 3 4 5", + `{{seq -5}}`: "1 0 -1 -2 -3 -4 -5", + `{{seq 0}}`: "1 0", + `{{seq 0 1 2 3}}`: "", + `{{seq 0 -4}}`: "0 -1 -2 -3 -4", } for tpl, expect := range tests { if err := runt(tpl, expect); err != nil {