Repository: elliotchance/pie
Pull request #129 (2019-05-12 09:20:24)

add drop func
add drop func

<!-- Reviewable:start -->
---
This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/elliotchance/pie/129)
<!-- Reviewable:end -->


codecov-io: # [Codecov](https://codecov.io/gh/elliotchance/pie/pull/129?src=pr&el=h1) Report
> :exclamation: No coverage uploaded for pull request base (`master@dc0f90e`). [Click here to learn what that means](https://docs.codecov.io/docs/error-reference#section-missing-base-commit).
> The diff coverage is `100%`.

[![Impacted file tree graph](https://codecov.io/gh/elliotchance/pie/pull/129/graphs/tree.svg?width=650&token=OvugwUQGM3&height=150&src=pr)](https://codecov.io/gh/elliotchance/pie/pull/129?src=pr&el=tree)

```diff
@@           Coverage Diff           @@
##             master   #129   +/-   ##
=======================================
  Coverage          ?   100%           
=======================================
  Files             ?      8           
  Lines             ?   1310           
  Branches          ?      0           
=======================================
  Hits              ?   1310           
  Misses            ?      0           
  Partials          ?      0
```


| [Impacted Files](https://codecov.io/gh/elliotchance/pie/pull/129?src=pr&el=tree) | Coverage Δ | |
|---|---|---|
| [pie/float64s\_pie.go](https://codecov.io/gh/elliotchance/pie/pull/129/diff?src=pr&el=tree#diff-cGllL2Zsb2F0NjRzX3BpZS5nbw==) | `100% <100%> (ø)` | |
| [pie/carpointers\_pie.go](https://codecov.io/gh/elliotchance/pie/pull/129/diff?src=pr&el=tree#diff-cGllL2NhcnBvaW50ZXJzX3BpZS5nbw==) | `100% <100%> (ø)` | |
| [pie/cars\_pie.go](https://codecov.io/gh/elliotchance/pie/pull/129/diff?src=pr&el=tree#diff-cGllL2NhcnNfcGllLmdv) | `100% <100%> (ø)` | |
| [pie/ints\_pie.go](https://codecov.io/gh/elliotchance/pie/pull/129/diff?src=pr&el=tree#diff-cGllL2ludHNfcGllLmdv) | `100% <100%> (ø)` | |
| [pie/strings\_pie.go](https://codecov.io/gh/elliotchance/pie/pull/129/diff?src=pr&el=tree#diff-cGllL3N0cmluZ3NfcGllLmdv) | `100% <100%> (ø)` | |

------

[Continue to review full report at Codecov](https://codecov.io/gh/elliotchance/pie/pull/129?src=pr&el=continue).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/elliotchance/pie/pull/129?src=pr&el=footer). Last update [dc0f90e...2602359](https://codecov.io/gh/elliotchance/pie/pull/129?src=pr&el=lastupdated). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments).


Patch:
diff --git a/README.md b/README.md
index a38c46f..55b7535 100644
--- a/README.md
+++ b/README.md
@@ -154,7 +154,7 @@ creates a lot of unused code. You can limit the functions generated by chaining
 the function names with a dot syntax, like:
 
 ```go
-//go:generate myInts.Average.Sum myStrings.Filter
+//go:generate pie myInts.Average.Sum myStrings.Filter
 ```
 
 This will only generate `myInts.Average`, `myInts.Sum` and `myStrings.Filter`.
@@ -183,6 +183,7 @@ The letters in brackets indicate:
 | `Bottom`          | ✓      | ✓      | ✓      |      | n        | Gets n elements from bottom. |
 | `Contains` (E)    | ✓      | ✓      | ✓      |      | n        | Check if the value exists in the slice. |
 | `Diff` (E)        | ✓      | ✓      | ✓      |      | n²       | Diff returns the elements that needs to be added or removed from the first slice to have the same elements in the second slice. |
+| `DropTop`         | ✓      | ✓      | ✓      |      | n        | A new slice after dropping the top n elements. |
 | `Each`            | ✓      | ✓      | ✓      |      | n        | Perform an action on each element. |
 | `Extend`          | ✓      | ✓      | ✓      |      | n        | A new slice with the elements from each slice appended to the end. |
 | `Filter`          | ✓      | ✓      | ✓      |      | n        | A new slice containing only the elements that returned true from the condition. |
diff --git a/functions/abs.go b/functions/abs.go
index ff8c63c..5edd3bc 100644
--- a/functions/abs.go
+++ b/functions/abs.go
@@ -1,14 +1,15 @@
 package functions
 
-import (
-	"math"
-)
-
 // Abs is a function which returns the absolute value of all the
 // elements in the slice.
 func (ss SliceType) Abs() SliceType {
+	result := make(SliceType, len(ss))
 	for i, val := range ss {
-		ss[i] = ElementType(math.Abs(float64(val)))
+		if val < 0 {
+			result[i] = -val
+		} else {
+			result[i] = val
+		}
 	}
-	return ss
+	return result
 }
diff --git a/functions/drop_top.go b/functions/drop_top.go
new file mode 100644
index 0000000..94f6a37
--- /dev/null
+++ b/functions/drop_top.go
@@ -0,0 +1,14 @@
+package functions
+
+// DropTop will return the rest slice after dropping the top n elements
+// if the slice has less elements then n that'll return empty slice
+// if n < 0 it'll return empty slice.
+func (ss SliceType) DropTop(n int) (drop SliceType) {
+	if n < 0 || n >= len(ss) {
+		return
+	}
+
+	drop = ss[n:]
+
+	return
+}
diff --git a/functions/main.go b/functions/main.go
index fa4adcc..a86c1a7 100644
--- a/functions/main.go
+++ b/functions/main.go
@@ -30,6 +30,7 @@ var Functions = []struct {
 	{"Bottom", "bottom.go", ForAll},
 	{"Contains", "contains.go", ForAll},
 	{"Diff", "diff.go", ForAll},
+	{"DropTop", "drop_top.go", ForAll},
 	{"Each", "each.go", ForAll},
 	{"Extend", "extend.go", ForAll},
 	{"Filter", "filter.go", ForAll},
diff --git a/main.go b/main.go
index 78f9399..6121759 100644
--- a/main.go
+++ b/main.go
@@ -4,7 +4,6 @@ package main
 
 import (
 	"fmt"
-	"github.com/elliotchance/pie/functions"
 	"go/ast"
 	"go/parser"
 	"go/token"
@@ -13,6 +12,8 @@ import (
 	"regexp"
 	"sort"
 	"strings"
+
+	"github.com/elliotchance/pie/functions"
 )
 
 func check(err error) {
@@ -186,7 +187,7 @@ func main() {
 		t = strings.Replace(t, "SliceType", mapOrSliceType, -1)
 
 		if !explorer.HasEquals() {
-			re := regexp.MustCompile(`([\w_]+)\.Equals\(([^)]+)\)`)
+			re := regexp.MustCompile(`([\w_]+|[\w_]+\[\w+\])\.Equals\(([^)]+)\)`)
 			t = ReplaceAllStringSubmatchFunc(re, t, func(groups []string) string {
 				return fmt.Sprintf("%s == %s", groups[1], groups[2])
 			})
diff --git a/pie/carpointers_pie.go b/pie/carpointers_pie.go
index 65048f8..3661f54 100755
--- a/pie/carpointers_pie.go
+++ b/pie/carpointers_pie.go
@@ -119,6 +119,19 @@ func (ss carPointers) Diff(against carPointers) (added, removed carPointers) {
 	return
 }
 
+// DropTop will return the rest slice after dropping the top n elements
+// if the slice has less elements then n that'll return empty slice
+// if n < 0 it'll return empty slice.
+func (ss carPointers) DropTop(n int) (drop carPointers) {
+	if n < 0 || n >= len(ss) {
+		return
+	}
+
+	drop = ss[n:]
+
+	return
+}
+
 // Each is more condensed version of Transform that allows an action to happen
 // on each elements and pass the original slice on.
 //
diff --git a/pie/cars_pie.go b/pie/cars_pie.go
index 58bae73..c49f5c6 100755
--- a/pie/cars_pie.go
+++ b/pie/cars_pie.go
@@ -119,6 +119,19 @@ func (ss cars) Diff(against cars) (added, removed cars) {
 	return
 }
 
+// DropTop will return the rest slice after dropping the top n elements
+// if the slice has less elements then n that'll return empty slice
+// if n < 0 it'll return empty slice.
+func (ss cars) DropTop(n int) (drop cars) {
+	if n < 0 || n >= len(ss) {
+		return
+	}
+
+	drop = ss[n:]
+
+	return
+}
+
 // Each is more condensed version of Transform that allows an action to happen
 // on each elements and pass the original slice on.
 //
diff --git a/pie/float64s_pie.go b/pie/float64s_pie.go
index 2fb8f85..a452c29 100755
--- a/pie/float64s_pie.go
+++ b/pie/float64s_pie.go
@@ -5,7 +5,6 @@ import (
 	"encoding/json"
 	"fmt"
 	"github.com/elliotchance/pie/pie/util"
-	"math"
 	"math/rand"
 	"sort"
 	"strconv"
@@ -14,10 +13,15 @@ import (
 // Abs is a function which returns the absolute value of all the
 // elements in the slice.
 func (ss Float64s) Abs() Float64s {
+	result := make(Float64s, len(ss))
 	for i, val := range ss {
-		ss[i] = float64(math.Abs(float64(val)))
+		if val < 0 {
+			result[i] = -val
+		} else {
+			result[i] = val
+		}
 	}
-	return ss
+	return result
 }
 
 // All will return true if all callbacks return true. It follows the same logic
@@ -153,6 +157,19 @@ func (ss Float64s) Diff(against Float64s) (added, removed Float64s) {
 	return
 }
 
+// DropTop will return the rest slice after dropping the top n elements
+// if the slice has less elements then n that'll return empty slice
+// if n < 0 it'll return empty slice.
+func (ss Float64s) DropTop(n int) (drop Float64s) {
+	if n < 0 || n >= len(ss) {
+		return
+	}
+
+	drop = ss[n:]
+
+	return
+}
+
 // Each is more condensed version of Transform that allows an action to happen
 // on each elements and pass the original slice on.
 //
diff --git a/pie/ints_pie.go b/pie/ints_pie.go
index e487573..49b58f9 100755
--- a/pie/ints_pie.go
+++ b/pie/ints_pie.go
@@ -5,7 +5,6 @@ import (
 	"encoding/json"
 	"fmt"
 	"github.com/elliotchance/pie/pie/util"
-	"math"
 	"math/rand"
 	"sort"
 	"strconv"
@@ -14,10 +13,15 @@ import (
 // Abs is a function which returns the absolute value of all the
 // elements in the slice.
 func (ss Ints) Abs() Ints {
+	result := make(Ints, len(ss))
 	for i, val := range ss {
-		ss[i] = int(math.Abs(float64(val)))
+		if val < 0 {
+			result[i] = -val
+		} else {
+			result[i] = val
+		}
 	}
-	return ss
+	return result
 }
 
 // All will return true if all callbacks return true. It follows the same logic
@@ -153,6 +157,19 @@ func (ss Ints) Diff(against Ints) (added, removed Ints) {
 	return
 }
 
+// DropTop will return the rest slice after dropping the top n elements
+// if the slice has less elements then n that'll return empty slice
+// if n < 0 it'll return empty slice.
+func (ss Ints) DropTop(n int) (drop Ints) {
+	if n < 0 || n >= len(ss) {
+		return
+	}
+
+	drop = ss[n:]
+
+	return
+}
+
 // Each is more condensed version of Transform that allows an action to happen
 // on each elements and pass the original slice on.
 //
diff --git a/pie/strings_pie.go b/pie/strings_pie.go
index a3b9716..a97e825 100755
--- a/pie/strings_pie.go
+++ b/pie/strings_pie.go
@@ -133,6 +133,19 @@ func (ss Strings) Diff(against Strings) (added, removed Strings) {
 	return
 }
 
+// DropTop will return the rest slice after dropping the top n elements
+// if the slice has less elements then n that'll return empty slice
+// if n < 0 it'll return empty slice.
+func (ss Strings) DropTop(n int) (drop Strings) {
+	if n < 0 || n >= len(ss) {
+		return
+	}
+
+	drop = ss[n:]
+
+	return
+}
+
 // Each is more condensed version of Transform that allows an action to happen
 // on each elements and pass the original slice on.
 //
diff --git a/template.go b/template.go
index 58c7fec..df9a6ad 100644
--- a/template.go
+++ b/template.go
@@ -4,17 +4,18 @@ package main
 var pieTemplates = map[string]string{
 	"Abs": `package functions
 
-import (
-	"math"
-)
-
 // Abs is a function which returns the absolute value of all the
 // elements in the slice.
 func (ss SliceType) Abs() SliceType {
+	result := make(SliceType, len(ss))
 	for i, val := range ss {
-		ss[i] = ElementType(math.Abs(float64(val)))
+		if val < 0 {
+			result[i] = -val
+		} else {
+			result[i] = val
+		}
 	}
-	return ss
+	return result
 }
 `,
 	"All": `package functions
@@ -171,6 +172,21 @@ func (ss SliceType) Diff(against SliceType) (added, removed SliceType) {
 
 	return
 }
+`,
+	"DropTop": `package functions
+
+// DropTop will return the rest slice after dropping the top n elements
+// if the slice has less elements then n that'll return empty slice
+// if n < 0 it'll return empty slice.
+func (ss SliceType) DropTop(n int) (drop SliceType) {
+	if n < 0 || n >= len(ss) {
+		return
+	}
+
+	drop = ss[n:]
+
+	return
+}
 `,
 	"Each": `package functions
 


Test patch:
diff --git a/pie/carpointers_test.go b/pie/carpointers_test.go
index 9459691..6601cd2 100644
--- a/pie/carpointers_test.go
+++ b/pie/carpointers_test.go
@@ -939,3 +939,54 @@ func TestCarPointers_SequenceUsing(t *testing.T) {
 		})
 	}
 }
+
+var carPointersDropTopTests = []struct {
+	ss      carPointers
+	n       int
+	dropTop carPointers
+}{
+	{
+		nil,
+		1,
+		nil,
+	},
+	{
+		carPointers{},
+		1,
+		nil,
+	},
+	{
+		carPointers{carPointerA, carPointerB},
+		-1,
+		nil,
+	},
+	{
+		carPointers{carPointerA, carPointerB},
+		0,
+		carPointers{carPointerA, carPointerB},
+	},
+	{
+		carPointers{carPointerA, carPointerB},
+		1,
+		carPointers{carPointerB},
+	},
+	{
+		carPointers{carPointerA, carPointerB},
+		2,
+		nil,
+	},
+	{
+		carPointers{carPointerA, carPointerB},
+		3,
+		nil,
+	},
+}
+
+func TestCarPointers_DropTop(t *testing.T) {
+	for _, test := range carPointersDropTopTests {
+		t.Run("", func(t *testing.T) {
+			defer assertImmutableCarPointers(t, &test.ss)()
+			assert.Equal(t, test.dropTop, test.ss.DropTop(test.n))
+		})
+	}
+}
diff --git a/pie/cars_test.go b/pie/cars_test.go
index d99e10f..bfcecb3 100644
--- a/pie/cars_test.go
+++ b/pie/cars_test.go
@@ -914,3 +914,54 @@ func TestCars_SequenceUsing(t *testing.T) {
 		})
 	}
 }
+
+var carsDropTopTests = []struct {
+	ss      cars
+	n       int
+	dropTop cars
+}{
+	{
+		nil,
+		1,
+		nil,
+	},
+	{
+		cars{},
+		1,
+		nil,
+	},
+	{
+		cars{car{"bar", "yellow"}, car{"Baz", "black"}},
+		-1,
+		nil,
+	},
+	{
+		cars{car{"bar", "yellow"}, car{"Baz", "black"}},
+		0,
+		cars{car{"bar", "yellow"}, car{"Baz", "black"}},
+	},
+	{
+		cars{car{"bar", "yellow"}, car{"Baz", "black"}},
+		1,
+		cars{car{"Baz", "black"}},
+	},
+	{
+		cars{car{"bar", "yellow"}, car{"Baz", "black"}},
+		2,
+		nil,
+	},
+	{
+		cars{car{"bar", "yellow"}, car{"Baz", "black"}},
+		3,
+		nil,
+	},
+}
+
+func TestCars_DropTop(t *testing.T) {
+	for _, test := range carsDropTopTests {
+		t.Run("", func(t *testing.T) {
+			defer assertImmutableCars(t, &test.ss)()
+			assert.Equal(t, test.dropTop, test.ss.DropTop(test.n))
+		})
+	}
+}
diff --git a/pie/float64s_test.go b/pie/float64s_test.go
index b1ef8e2..fb49044 100644
--- a/pie/float64s_test.go
+++ b/pie/float64s_test.go
@@ -1101,3 +1101,55 @@ func TestFloat64s_Float64s(t *testing.T) {
 		Float64s{92.384, 823.324, 453},
 		Float64s{92.384, 823.324, 453}.Float64s())
 }
+
+var float64sDropTopTests = []struct {
+	ss      Float64s
+	n       int
+	dropTop Float64s
+}{
+	{
+		nil,
+		1,
+		nil,
+	},
+	{
+		Float64s{},
+		1,
+		nil,
+	},
+	{
+		Float64s{1.23, 2.34},
+		-1,
+		nil,
+	},
+	{
+		Float64s{1.23, 2.34},
+		0,
+		Float64s{1.23, 2.34},
+	},
+
+	{
+		Float64s{1.23, 2.34},
+		1,
+		Float64s{2.34},
+	},
+	{
+		Float64s{1.23, 2.34},
+		2,
+		nil,
+	},
+	{
+		Float64s{1.23, 2.34},
+		3,
+		nil,
+	},
+}
+
+func TestFloat64s_DropTop(t *testing.T) {
+	for _, test := range float64sDropTopTests {
+		t.Run("", func(t *testing.T) {
+			defer assertImmutableFloat64s(t, &test.ss)()
+			assert.Equal(t, test.dropTop, test.ss.DropTop(test.n))
+		})
+	}
+}
diff --git a/pie/ints_test.go b/pie/ints_test.go
index 119de99..8121c21 100644
--- a/pie/ints_test.go
+++ b/pie/ints_test.go
@@ -772,6 +772,22 @@ func TestInts_Abs(t *testing.T) {
 	assert.Equal(t, Ints{1, 2}, Ints{1, 2}.Abs())
 }
 
+func TestInts_AbsLarge(t *testing.T) {
+	// int64: prevent compile error (constant overflow) on 32-bit architectures.
+	a64 := []int64{3, -4, 1234567890123456789, -987654321098765432}
+	var a Ints
+	for _, v := range a64 {
+		a = a.Append(int(v))
+	}
+	b := a.Abs()
+	for i := range a {
+		v, absv := a[i], b[i]
+		if absv != v && absv != -v {
+			t.Errorf("Incorrect result for Abs(%d): %d", v, absv)
+		}
+	}
+}
+
 var intsSendTests = []struct {
 	ss            Ints
 	recieveDelay  time.Duration
@@ -1066,3 +1082,55 @@ func TestInts_Float64s(t *testing.T) {
 		Float64s{92, 823, 453},
 		Ints{92, 823, 453}.Float64s())
 }
+
+var intsDropTopTests = []struct {
+	ss      Ints
+	n       int
+	dropTop Ints
+}{
+	{
+		nil,
+		1,
+		nil,
+	},
+	{
+		Ints{},
+		1,
+		nil,
+	},
+	{
+		Ints{1, 2},
+		-1,
+		nil,
+	},
+	{
+		Ints{1, 2},
+		0,
+		Ints{1, 2},
+	},
+
+	{
+		Ints{1, 2},
+		1,
+		Ints{2},
+	},
+	{
+		Ints{1, 2},
+		2,
+		nil,
+	},
+	{
+		Ints{1, 2},
+		3,
+		nil,
+	},
+}
+
+func TestInts_DropTop(t *testing.T) {
+	for _, test := range intsDropTopTests {
+		t.Run("", func(t *testing.T) {
+			defer assertImmutableInts(t, &test.ss)()
+			assert.Equal(t, test.dropTop, test.ss.DropTop(test.n))
+		})
+	}
+}
diff --git a/pie/strings_test.go b/pie/strings_test.go
index e608488..8a549a9 100644
--- a/pie/strings_test.go
+++ b/pie/strings_test.go
@@ -1095,3 +1095,55 @@ func TestStrings_SequenceUsing(t *testing.T) {
 		})
 	}
 }
+
+var stringsDropTopTests = []struct {
+	ss      Strings
+	n       int
+	dropTop Strings
+}{
+	{
+		nil,
+		1,
+		nil,
+	},
+	{
+		Strings{},
+		1,
+		nil,
+	},
+	{
+		Strings{"foo", "bar"},
+		-1,
+		nil,
+	},
+	{
+		Strings{"foo", "bar"},
+		0,
+		Strings{"foo", "bar"},
+	},
+
+	{
+		Strings{"foo", "bar"},
+		1,
+		Strings{"bar"},
+	},
+	{
+		Strings{"foo", "bar"},
+		2,
+		nil,
+	},
+	{
+		Strings{"foo", "bar"},
+		3,
+		nil,
+	},
+}
+
+func TestStrings_DropTop(t *testing.T) {
+	for _, test := range stringsDropTopTests {
+		t.Run("", func(t *testing.T) {
+			defer assertImmutableStrings(t, &test.ss)()
+			assert.Equal(t, test.dropTop, test.ss.DropTop(test.n))
+		})
+	}
+}