Repository: elliotchance/pie
Pull request #159 (2020-02-04 15:08:54)

Implement pop


<!-- 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/159)
<!-- Reviewable:end -->


codecov-io: # [Codecov](https://codecov.io/gh/elliotchance/pie/pull/159?src=pr&el=h1) Report
> :exclamation: No coverage uploaded for pull request base (`master@f0fd3b3`). [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/159/graphs/tree.svg?width=650&token=OvugwUQGM3&height=150&src=pr)](https://codecov.io/gh/elliotchance/pie/pull/159?src=pr&el=tree)

```diff
@@            Coverage Diff            @@
##             master     #159   +/-   ##
=========================================
  Coverage          ?   98.63%           
=========================================
  Files             ?        8           
  Lines             ?     1762           
  Branches          ?        0           
=========================================
  Hits              ?     1738           
  Misses            ?       12           
  Partials          ?       12
```


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

------

[Continue to review full report at Codecov](https://codecov.io/gh/elliotchance/pie/pull/159?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/159?src=pr&el=footer). Last update [f0fd3b3...8817b7b](https://codecov.io/gh/elliotchance/pie/pull/159?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 23b3b8a..daa8251 100644
--- a/README.md
+++ b/README.md
@@ -211,6 +211,7 @@ The letters in brackets indicate:
 | [`Median`](#median)                     |        | ✓      |        |      | n        | Median returns the value separating the higher half from the lower half of a data sample.  |
 | [`Min`](#min)                           | ✓      | ✓      |        |      | n        | Min is the minimum value, or zero.  |
 | [`Mode`](#mode)                         | ✓      | ✓      | ✓      |      | n        | Mode returns a new slice containing the most frequently occuring values.  |
+| [`Pop`](#pop)                           | ✓      | ✓      | ✓      |      | n        | Pop the first element of the slice  |
 | [`Product`](#product)                   |        | ✓      |        |      | n        | Product is the product of all of the elements.  |
 | [`Random`](#random)                     | ✓      | ✓      | ✓      |      | 1        | Random returns a random element by your rand.Source, or zero  |
 | [`Reduce`](#reduce)                     | ✓      | ✓      |        |      | n        | Reduce continually applies the provided function over the slice. Reducing the elements to a single value.  |
@@ -541,6 +542,23 @@ The number of items returned may be the same as the input or less. It will
 never return zero items unless the input slice has zero items.
 
 
+## Pop
+
+Pop the first element of the slice
+
+
+Usage Example:
+
+
+```go
+type knownGreetings []string
+greetings := knownGreetings{"ciao", "hello", "hola"}
+for greeting := greetings.Pop(); greeting != nil; greeting = greetings.Pop() {
+    fmt.Println(*greeting)
+}
+
+```
+
 ## Product
 
 Product is the product of all of the elements.
diff --git a/functions/main.go b/functions/main.go
index 8d96ac2..752be4f 100644
--- a/functions/main.go
+++ b/functions/main.go
@@ -58,6 +58,7 @@ var Functions = []struct {
 	{"Median", "median.go", ForNumbers, "n"},
 	{"Min", "min.go", ForNumbersAndStrings, "n"},
 	{"Mode", "mode.go", ForAll, "n"},
+	{"Pop", "pop.go", ForAll, "n"},
 	{"Product", "product.go", ForNumbers, "n"},
 	{"Random", "random.go", ForAll, "1"},
 	{"Reduce", "reduce.go", ForNumbersAndStrings, "n"},
diff --git a/functions/pop.go b/functions/pop.go
new file mode 100644
index 0000000..479234f
--- /dev/null
+++ b/functions/pop.go
@@ -0,0 +1,21 @@
+package functions
+
+// Pop the first element of the slice
+//
+// Usage Example:
+//
+//   type knownGreetings []string
+//   greetings := knownGreetings{"ciao", "hello", "hola"}
+//   for greeting := greetings.Pop(); greeting != nil; greeting = greetings.Pop() {
+//       fmt.Println(*greeting)
+//   }
+func (ss *SliceType) Pop() (popped *ElementType) {
+
+	if len(*ss) == 0 {
+		return
+	}
+
+	popped = &(*ss)[0]
+	*ss = (*ss)[1:]
+	return
+}
diff --git a/pie/carpointers_pie.go b/pie/carpointers_pie.go
index b248b76..0f5755a 100755
--- a/pie/carpointers_pie.go
+++ b/pie/carpointers_pie.go
@@ -433,6 +433,26 @@ func (ss carPointers) Mode() carPointers {
 	return maxValues
 }
 
+// Pop the first element of the slice
+//
+// Usage Example:
+//
+//   type knownGreetings []string
+//   greetings := knownGreetings{"ciao", "hello", "hola"}
+//   for greeting := greetings.Pop(); greeting != nil; greeting = greetings.Pop() {
+//       fmt.Println(*greeting)
+//   }
+func (ss *carPointers) Pop() (popped **car) {
+
+	if len(*ss) == 0 {
+		return
+	}
+
+	popped = &(*ss)[0]
+	*ss = (*ss)[1:]
+	return
+}
+
 // Random returns a random element by your rand.Source, or zero
 func (ss carPointers) Random(source rand.Source) *car {
 	n := len(ss)
diff --git a/pie/cars_pie.go b/pie/cars_pie.go
index 0808f74..9f6ef4f 100755
--- a/pie/cars_pie.go
+++ b/pie/cars_pie.go
@@ -433,6 +433,26 @@ func (ss cars) Mode() cars {
 	return maxValues
 }
 
+// Pop the first element of the slice
+//
+// Usage Example:
+//
+//   type knownGreetings []string
+//   greetings := knownGreetings{"ciao", "hello", "hola"}
+//   for greeting := greetings.Pop(); greeting != nil; greeting = greetings.Pop() {
+//       fmt.Println(*greeting)
+//   }
+func (ss *cars) Pop() (popped *car) {
+
+	if len(*ss) == 0 {
+		return
+	}
+
+	popped = &(*ss)[0]
+	*ss = (*ss)[1:]
+	return
+}
+
 // Random returns a random element by your rand.Source, or zero
 func (ss cars) Random(source rand.Source) car {
 	n := len(ss)
diff --git a/pie/float64s_pie.go b/pie/float64s_pie.go
index b800800..a2e7803 100755
--- a/pie/float64s_pie.go
+++ b/pie/float64s_pie.go
@@ -613,6 +613,26 @@ func (ss Float64s) Mode() Float64s {
 	return maxValues
 }
 
+// Pop the first element of the slice
+//
+// Usage Example:
+//
+//   type knownGreetings []string
+//   greetings := knownGreetings{"ciao", "hello", "hola"}
+//   for greeting := greetings.Pop(); greeting != nil; greeting = greetings.Pop() {
+//       fmt.Println(*greeting)
+//   }
+func (ss *Float64s) Pop() (popped *float64) {
+
+	if len(*ss) == 0 {
+		return
+	}
+
+	popped = &(*ss)[0]
+	*ss = (*ss)[1:]
+	return
+}
+
 // Product is the product of all of the elements.
 func (ss Float64s) Product() (product float64) {
 	if len(ss) == 0 {
diff --git a/pie/ints_pie.go b/pie/ints_pie.go
index 11ea71b..2a02d30 100755
--- a/pie/ints_pie.go
+++ b/pie/ints_pie.go
@@ -613,6 +613,26 @@ func (ss Ints) Mode() Ints {
 	return maxValues
 }
 
+// Pop the first element of the slice
+//
+// Usage Example:
+//
+//   type knownGreetings []string
+//   greetings := knownGreetings{"ciao", "hello", "hola"}
+//   for greeting := greetings.Pop(); greeting != nil; greeting = greetings.Pop() {
+//       fmt.Println(*greeting)
+//   }
+func (ss *Ints) Pop() (popped *int) {
+
+	if len(*ss) == 0 {
+		return
+	}
+
+	popped = &(*ss)[0]
+	*ss = (*ss)[1:]
+	return
+}
+
 // Product is the product of all of the elements.
 func (ss Ints) Product() (product int) {
 	if len(ss) == 0 {
diff --git a/pie/strings_pie.go b/pie/strings_pie.go
index 7bb650a..297cd04 100755
--- a/pie/strings_pie.go
+++ b/pie/strings_pie.go
@@ -524,6 +524,26 @@ func (ss Strings) Mode() Strings {
 	return maxValues
 }
 
+// Pop the first element of the slice
+//
+// Usage Example:
+//
+//   type knownGreetings []string
+//   greetings := knownGreetings{"ciao", "hello", "hola"}
+//   for greeting := greetings.Pop(); greeting != nil; greeting = greetings.Pop() {
+//       fmt.Println(*greeting)
+//   }
+func (ss *Strings) Pop() (popped *string) {
+
+	if len(*ss) == 0 {
+		return
+	}
+
+	popped = &(*ss)[0]
+	*ss = (*ss)[1:]
+	return
+}
+
 // Random returns a random element by your rand.Source, or zero
 func (ss Strings) Random(source rand.Source) string {
 	n := len(ss)
diff --git a/template.go b/template.go
index 7a0496b..65f7db3 100644
--- a/template.go
+++ b/template.go
@@ -729,6 +729,28 @@ func (ss SliceType) Mode() SliceType {
 
 	return maxValues
 }
+`,
+	"Pop": `package functions
+
+// Pop the first element of the slice
+//
+// Usage Example:
+//
+//   type knownGreetings []string
+//   greetings := knownGreetings{"ciao", "hello", "hola"}
+//   for greeting := greetings.Pop(); greeting != nil; greeting = greetings.Pop() {
+//       fmt.Println(*greeting)
+//   }
+func (ss *SliceType) Pop() (popped *ElementType) {
+
+	if len(*ss) == 0 {
+		return
+	}
+
+	popped = &(*ss)[0]
+	*ss = (*ss)[1:]
+	return
+}
 `,
 	"Product": `package functions
 


Test patch:
diff --git a/pie/carpointers_test.go b/pie/carpointers_test.go
index c3bec79..fe34f4a 100644
--- a/pie/carpointers_test.go
+++ b/pie/carpointers_test.go
@@ -1343,3 +1343,19 @@ func TestCarPointers_Join(t *testing.T) {
 	car1, car2 := &car{Name: "maverick", Color: "red"}, &car{Name: "ferrari", Color: "red"}
 	assert.Equal(t, "maverick is red-ferrari is red", carPointers{car1, car2}.Join("-"))
 }
+
+func TestCarPointers_Pop(t *testing.T) {
+	car1, car2 := &car{Name: "maverick", Color: "red"}, &car{Name: "ferrari", Color: "red"}
+
+	cars := carPointers{car1, car2}
+
+	assert.Equal(t, &car1, cars.Pop())
+	assert.Equal(t, carPointers{car2}, cars)
+
+	assert.Equal(t, &car2, cars.Pop())
+	assert.Equal(t, carPointers{}, cars)
+
+	assert.Equal(t, (**car)(nil), cars.Pop())
+	assert.Equal(t, carPointers{}, cars)
+
+}
diff --git a/pie/cars_test.go b/pie/cars_test.go
index b04621b..bcb2cd0 100644
--- a/pie/cars_test.go
+++ b/pie/cars_test.go
@@ -1316,3 +1316,19 @@ func TestCars_Join(t *testing.T) {
 	car1, car2 := car{Name: "maverick", Color: "red"}, car{Name: "ferrari", Color: "red"}
 	assert.Equal(t, "{maverick red}-{ferrari red}", cars{car1, car2}.Join("-"))
 }
+
+func TestCars_Pop(t *testing.T) {
+	car1, car2 := car{Name: "maverick", Color: "red"}, car{Name: "ferrari", Color: "red"}
+
+	garage := cars{car1, car2}
+
+	assert.Equal(t, &car1, garage.Pop())
+	assert.Equal(t, cars{car2}, garage)
+
+	assert.Equal(t, &car2, garage.Pop())
+	assert.Equal(t, cars{}, garage)
+
+	assert.Equal(t, (*car)(nil), garage.Pop())
+	assert.Equal(t, cars{}, garage)
+
+}
diff --git a/pie/float64s_test.go b/pie/float64s_test.go
index 763161a..10447d1 100644
--- a/pie/float64s_test.go
+++ b/pie/float64s_test.go
@@ -1489,6 +1489,17 @@ func TestFloat64s_Join(t *testing.T) {
 	assert.Equal(t, "0.1;2e+16", Float64s{f1, f2}.Join(";"))
 }
 
+func TestFloat64s_Pop(t *testing.T) {
+
+	numbers := Float64s{42.0, 4.2}
+
+	assert.Equal(t, 42.0, *numbers.Pop())
+	assert.Equal(t, Float64s{4.2}, numbers)
+
+	assert.Equal(t, 4.2, *numbers.Pop())
+	assert.Equal(t, Float64s{}, numbers)
+}
+
 func TestFloat64s_Group(t *testing.T) {
 	assert.Equal(t, map[float64]int{}, Float64s(nil).Group())
 
diff --git a/pie/ints_test.go b/pie/ints_test.go
index ab7ae35..9ccdc44 100644
--- a/pie/ints_test.go
+++ b/pie/ints_test.go
@@ -1478,6 +1478,17 @@ func TestInts_Join(t *testing.T) {
 	assert.Equal(t, "1--2-3", Ints{1, -2, 3}.Join("-"))
 }
 
+func TestInts_Pop(t *testing.T) {
+
+	numbers := Ints{42, 999}
+
+	assert.Equal(t, 42, *numbers.Pop())
+	assert.Equal(t, Ints{999}, numbers)
+
+	assert.Equal(t, 999, *numbers.Pop())
+	assert.Equal(t, Ints{}, numbers)
+}
+
 func TestInts_Group(t *testing.T) {
 	assert.Equal(t, map[int]int{}, Ints(nil).Group())
 
diff --git a/pie/strings_test.go b/pie/strings_test.go
index 2cc0a62..4be41b7 100644
--- a/pie/strings_test.go
+++ b/pie/strings_test.go
@@ -1502,6 +1502,17 @@ func TestStrings_ShiftAndUnshift(t *testing.T) {
 	}
 }
 
+func TestStrings_Pop(t *testing.T) {
+
+	foobar := Strings{"foo", "bar"}
+
+	assert.Equal(t, "foo", *foobar.Pop())
+	assert.Equal(t, Strings{"bar"}, foobar)
+
+	assert.Equal(t, "bar", *foobar.Pop())
+	assert.Equal(t, Strings{}, foobar)
+}
+
 func TestStrings_Group(t *testing.T) {
 	assert.Equal(t, map[string]int{}, Strings(nil).Group())