Skip to content

Commit

Permalink
Add Delete function (#194)
Browse files Browse the repository at this point in the history
Delete removes elements at indices in idx from input slice, returns resulting slice.
If an index is out of bounds, skip it.
  • Loading branch information
chocolacula authored Jun 19, 2023
1 parent 90bf328 commit 36b1ca2
Show file tree
Hide file tree
Showing 8 changed files with 138 additions and 2 deletions.
35 changes: 35 additions & 0 deletions v2/delete.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package pie

import "sort"

// Removes elements at indices in idx from input slice, returns resulting slice.
// If an index is out of bounds, skip it.
func Delete[T any](ss []T, idx ...int) []T {
// short path O(n) inplace
if len(idx) == 1 {
i := idx[0]

if i < 0 || i >= len(ss) {
return ss
}
return append(ss[:i], ss[i+1:]...)
}

// long path O(mLog(m) + n)
sort.Ints(idx)

ss2 := make([]T, 0, len(ss))

prev := 0
for _, i := range idx {
if i < 0 || i >= len(ss) {
continue
}
// Copy by consecutive chunks instead of one by one
ss2 = append(ss2, ss[prev:i]...)
prev = i + 1
}
ss2 = append(ss2, ss[prev:]...)

return ss2
}
61 changes: 61 additions & 0 deletions v2/delete_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
package pie_test

import (
"github.com/elliotchance/pie/v2"
"github.com/stretchr/testify/assert"
"testing"
)

var deleteTests = []struct {
ss []int
idx []int
expected []int
}{
// idx out of bounds
{
[]int{1, 2},
[]int{-1},
[]int{1, 2},
},
{
[]int{1, 2},
[]int{2},
[]int{1, 2},
},
// remove from empty slice
{
[]int{},
[]int{0},
[]int{},
},
{
[]int{1},
[]int{0},
[]int{},
},
{
[]int{1, 2, 3, 4, 5},
[]int{2},
[]int{1, 2, 4, 5},
},
{
[]int{1, 2, 3, 4, 5},
[]int{1, 3},
[]int{1, 3, 5},
},
// mixed indices
{
[]int{1, 2, 3, 4, 5},
[]int{1, -1, 5, 3},
[]int{1, 3, 5},
},
}

func TestDelete(t *testing.T) {
for _, test := range deleteTests {

t.Run("", func(t *testing.T) {
assert.Equal(t, test.expected, pie.Delete(test.ss, test.idx...))
})
}
}
6 changes: 6 additions & 0 deletions v2/of.go
Original file line number Diff line number Diff line change
Expand Up @@ -203,3 +203,9 @@ func (o OfSlice[T]) Top(n int) OfSlice[T] {
func (o OfSlice[T]) Unshift(elements ...T) OfSlice[T] {
return OfSlice[T]{Unshift(o.Result, elements...)}
}

// Removes element at index in idx from input slice, returns resulting slice.
// If an index in idx out of bounds, skip it.
func (o OfSlice[T]) Delete(idx ...int) OfSlice[T] {
return OfSlice[T]{Delete(o.Result, idx...)}
}
7 changes: 6 additions & 1 deletion v2/of_numeric.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,9 @@ package pie

import (
"context"
"golang.org/x/exp/constraints"
"math/rand"

"golang.org/x/exp/constraints"
)

// OfNumeric encapsulates a slice to be used in multiple chained operations.
Expand Down Expand Up @@ -231,3 +232,7 @@ func (o OfNumericSlice[T]) Unique() OfNumericSlice[T] {
func (o OfNumericSlice[T]) Unshift(elements ...T) OfNumericSlice[T] {
return OfNumericSlice[T]{Unshift(o.Result, elements...)}
}

func (o OfNumericSlice[T]) Delete(idx ...int) OfNumericSlice[T] {
return OfNumericSlice[T]{Delete(o.Result, idx...)}
}
8 changes: 8 additions & 0 deletions v2/of_numeric_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,4 +23,12 @@ func TestOfONumeric(t *testing.T) {

assert.Equal(t, []float64{1.23}, names)
})

t.Run("delete", func(t *testing.T) {
names := pie.OfNumeric([]float64{1.23, 4.56}).
Delete(1).
Result

assert.Equal(t, []float64{1.23}, names)
})
}
7 changes: 6 additions & 1 deletion v2/of_ordered.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,9 @@ package pie

import (
"context"
"golang.org/x/exp/constraints"
"math/rand"

"golang.org/x/exp/constraints"
)

// OfOrdered encapsulates a slice to be used in multiple chained operations.
Expand Down Expand Up @@ -199,3 +200,7 @@ func (o OfOrderedSlice[T]) Unique() OfOrderedSlice[T] {
func (o OfOrderedSlice[T]) Unshift(elements ...T) OfOrderedSlice[T] {
return OfOrderedSlice[T]{Unshift(o.Result, elements...)}
}

func (o OfOrderedSlice[T]) Delete(idx ...int) OfOrderedSlice[T] {
return OfOrderedSlice[T]{Delete(o.Result, idx...)}
}
8 changes: 8 additions & 0 deletions v2/of_ordered_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,4 +23,12 @@ func TestOfOrdered(t *testing.T) {

assert.Equal(t, []string{"Bob"}, names)
})

t.Run("delete", func(t *testing.T) {
names := pie.Of([]string{"Bob", "Sally", "John", "Jane"}).
Delete(2, 3).
Result

assert.Equal(t, []string{"Bob", "Sally"}, names)
})
}
8 changes: 8 additions & 0 deletions v2/of_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,4 +28,12 @@ func TestOf(t *testing.T) {

assert.Equal(t, []string{"Bob", "Sally"}, names)
})

t.Run("delete", func(t *testing.T) {
names := pie.Of([]string{"Bob", "Sally", "John", "Jane"}).
Delete(2, 3).
Result

assert.Equal(t, []string{"Bob", "Sally"}, names)
})
}

0 comments on commit 36b1ca2

Please sign in to comment.