Skip to content

Commit

Permalink
Added DropByIndex helper for slice (#398)
Browse files Browse the repository at this point in the history
* added DropByIndex helper

---------

Co-authored-by: Samuel Berthe <dev@samuel-berthe.fr>
  • Loading branch information
phith0n and samber committed Jun 29, 2024
1 parent 93686db commit 52e17fa
Show file tree
Hide file tree
Showing 5 changed files with 95 additions and 0 deletions.
12 changes: 12 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -747,6 +747,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"

"github.com/samber/lo/internal/constraints"
Expand Down Expand Up @@ -417,6 +418,38 @@ func DropRightWhile[T any, Slice ~[]T](collection Slice, predicate func(item 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[T any, Slice ~[]T](collection Slice, predicate func(item T, index int) bool) Slice {
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
21 changes: 21 additions & 0 deletions slice_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -571,6 +571,27 @@ func TestDropRightWhile(t *testing.T) {
is.IsType(nonempty, allStrings, "type preserved")
}

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

0 comments on commit 52e17fa

Please sign in to comment.