Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added DropByIndex helper for slice #398

Merged
merged 7 commits into from
Jun 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -716,6 +716,18 @@ l := lo.DropRightWhile([]string{"a", "aa", "aaa", "aa", "aa"}, func(val string)

[[play](https://go.dev/play/p/3-n71oEC0Hz)]

### DropByIndex

Drops elements from a slice or array by the index. A negative index will drop elements from the end of the slice.

```go
l := lo.Drop([]int{0, 1, 2, 3, 4, 5}, 2, 4, -1)
// []int{2, 3}
```

[[play](https://go.dev/play/p/JswS7vXRJP2)]


### Reject

The opposite of Filter, this method returns the elements of collection that predicate does not return truthy for.
Expand Down
33 changes: 33 additions & 0 deletions slice.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package lo

import (
"sort"
"math/rand"

"golang.org/x/exp/constraints"
Expand Down Expand Up @@ -417,6 +418,38 @@ func DropRightWhile[T any](collection []T, predicate func(item T) bool) []T {
return append(result, collection[:i+1]...)
}

// DropByIndex drops elements from a slice or array by the index.
// A negative index will drop elements from the end of the slice.
// Play: https://go.dev/play/p/bPIH4npZRxS
func DropByIndex[T any](collection []T, indexes ...int) []T {
initialSize := len(collection)
if initialSize == 0 {
return make([]T, 0)
}

for i := range indexes {
if indexes[i] < 0 {
indexes[i] = initialSize + indexes[i]
}
}

indexes = Uniq(indexes)
sort.Ints(indexes)

result := make([]T, 0, initialSize)
result = append(result, collection...)

for i := range indexes {
if indexes[i]-i < 0 || indexes[i]-i >= initialSize-i {
continue
}

result = append(result[:indexes[i]-i], result[indexes[i]-i+1:]...)
}

return result
}

// Reject is the opposite of Filter, this method returns the elements of collection that predicate does not return truthy for.
// Play: https://go.dev/play/p/YkLMODy1WEL
func Reject[V any](collection []V, predicate func(item V, index int) bool) []V {
Expand Down
20 changes: 20 additions & 0 deletions slice_benchmark_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,26 @@ func BenchmarkDropRightWhile(b *testing.B) {
}
}

func BenchmarkDropByIndex(b *testing.B) {
for _, n := range lengths {
strs := genSliceString(n)
b.Run(fmt.Sprintf("strings_%d", n), func(b *testing.B) {
for i := 0; i < b.N; i++ {
_ = DropByIndex(strs, n/4)
}
})
}

for _, n := range lengths {
ints := genSliceInt(n)
b.Run(fmt.Sprintf("ints%d", n), func(b *testing.B) {
for i := 0; i < b.N; i++ {
_ = DropByIndex(ints, n/4)
}
})
}
}

func BenchmarkReplace(b *testing.B) {
lengths := []int{1_000, 10_000, 100_000}
for _, n := range lengths {
Expand Down
9 changes: 9 additions & 0 deletions slice_example_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -296,6 +296,15 @@ func ExampleDropRightWhile() {
// Output: [0 1 2]
}

func ExampleDropByIndex() {
list := []int{0, 1, 2, 3, 4, 5}

result := DropByIndex(list, 2)

fmt.Printf("%v", result)
// Output: [0 1 3 4 5]
}

func ExampleReject() {
list := []int{0, 1, 2, 3, 4, 5}

Expand Down
25 changes: 23 additions & 2 deletions slice_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -388,7 +388,7 @@ func TestAssociate(t *testing.T) {

func TestSliceToMap(t *testing.T) {
t.Parallel()

type foo struct {
baz string
bar int
Expand Down Expand Up @@ -483,6 +483,27 @@ func TestDropRightWhile(t *testing.T) {
}))
}

func TestDropByIndex(t *testing.T) {
t.Parallel()
is := assert.New(t)

is.Equal([]int{1, 2, 3, 4}, DropByIndex([]int{0, 1, 2, 3, 4}, 0))
is.Equal([]int{3, 4}, DropByIndex([]int{0, 1, 2, 3, 4}, 0, 1, 2))
is.Equal([]int{0, 4}, DropByIndex([]int{0, 1, 2, 3, 4}, -4, -2, -3))
is.Equal([]int{0, 2, 3, 4}, DropByIndex([]int{0, 1, 2, 3, 4}, -4, -4))
is.Equal([]int{2, 4}, DropByIndex([]int{0, 1, 2, 3, 4}, 3, 1, 0))
is.Equal([]int{0, 1, 3, 4}, DropByIndex([]int{0, 1, 2, 3, 4}, 2))
is.Equal([]int{0, 1, 2, 3}, DropByIndex([]int{0, 1, 2, 3, 4}, 4))
is.Equal([]int{0, 1, 2, 3, 4}, DropByIndex([]int{0, 1, 2, 3, 4}, 5))
is.Equal([]int{0, 1, 2, 3, 4}, DropByIndex([]int{0, 1, 2, 3, 4}, 100))
is.Equal([]int{0, 1, 2, 3}, DropByIndex([]int{0, 1, 2, 3, 4}, -1))
is.Equal([]int{}, DropByIndex([]int{}, 0, 1))
is.Equal([]int{}, DropByIndex([]int{42}, 0, 1))
is.Equal([]int{}, DropByIndex([]int{42}, 1, 0))
is.Equal([]int{}, DropByIndex([]int{}, 1))
is.Equal([]int{}, DropByIndex([]int{1}, 0))
}

func TestReject(t *testing.T) {
t.Parallel()
is := assert.New(t)
Expand Down Expand Up @@ -626,7 +647,7 @@ func TestSlice(t *testing.T) {
out16 := Slice(in, -10, 1)
out17 := Slice(in, -1, 3)
out18 := Slice(in, -10, 7)

is.Equal([]int{}, out1)
is.Equal([]int{0}, out2)
is.Equal([]int{0, 1, 2, 3, 4}, out3)
Expand Down
Loading