Skip to content
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
30 changes: 30 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ You can import `lo` using:
import (
"github.com/samber/lo"
lop "github.com/samber/lo/parallel"
lom "github.com/samber/lo/mutable"
)
```

Expand Down Expand Up @@ -344,6 +345,23 @@ even := lo.Filter([]int{1, 2, 3, 4}, func(x int, index int) bool {

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

Mutable: like `lo.Filter()`, but the slice is updated in place.

```go
import lom "github.com/samber/lo/mutable"

list := []int{1, 2, 3, 4}
newList := lom.Filter(list, func(x int) bool {
return x%2 == 0
})

list
// []int{2, 4, 3, 4}

newList
// []int{2, 4}
```

### Map

Manipulates a slice of one type and transforms it into a slice of another type:
Expand All @@ -370,6 +388,18 @@ lop.Map([]int64{1, 2, 3, 4}, func(x int64, _ int) string {
// []string{"1", "2", "3", "4"}
```

Mutable: like `lo.Map()`, but the slice is updated in place.

```go
import lom "github.com/samber/lo/mutable"

list := []int{1, 2, 3, 4}
lom.Map(list, func(x int) int {
return i*2
})
// []int{2, 4, 6, 8}
```

### UniqMap

Manipulates a slice and transforms it to a slice of another type with unique values.
Expand Down
48 changes: 48 additions & 0 deletions mutable/slice.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,54 @@ package mutable

import "github.com/samber/lo/internal/rand"

// Filter is a generic function that modifies the input slice in-place to contain only the elements
// that satisfy the provided predicate function. The predicate function takes an element of the slice and its index,
// and should return true for elements that should be kept and false for elements that should be removed.
// The function returns the modified slice, which may be shorter than the original if some elements were removed.
// Note that the order of elements in the original slice is preserved in the output.
func Filter[T any, Slice ~[]T](collection Slice, predicate func(item T) bool) Slice {
j := 0
for _, item := range collection {
if predicate(item) {
collection[j] = item
j++
}
}
return collection[:j]
}

// FilterI is a generic function that modifies the input slice in-place to contain only the elements
// that satisfy the provided predicate function. The predicate function takes an element of the slice and its index,
// and should return true for elements that should be kept and false for elements that should be removed.
// The function returns the modified slice, which may be shorter than the original if some elements were removed.
// Note that the order of elements in the original slice is preserved in the output.
func FilterI[T any, Slice ~[]T](collection Slice, predicate func(item T, index int) bool) Slice {
j := 0
for i, item := range collection {
if predicate(item, i) {
collection[j] = item
j++
}
}
return collection[:j]
}

// Map is a generic function that modifies the input slice in-place to contain the result of applying the provided
// function to each element of the slice. The function returns the modified slice, which has the same length as the original.
func Map[T any, Slice ~[]T](collection Slice, fn func(item T) T) {
for i := range collection {
collection[i] = fn(collection[i])
}
}

// MapI is a generic function that modifies the input slice in-place to contain the result of applying the provided
// function to each element of the slice. The function returns the modified slice, which has the same length as the original.
func MapI[T any, Slice ~[]T](collection Slice, fn func(item T, index int) T) {
for i := range collection {
collection[i] = fn(collection[i], i)
}
}

// Shuffle returns an array of shuffled values. Uses the Fisher-Yates shuffle algorithm.
// Play: https://go.dev/play/p/2xb3WdLjeSJ
func Shuffle[T any, Slice ~[]T](collection Slice) {
Expand Down
48 changes: 48 additions & 0 deletions mutable/slice_example_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,54 @@ package mutable

import "fmt"

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

newList := Filter(list, func(nbr int) bool {
return nbr%2 == 0
})

fmt.Printf("%v\n%v", list, newList)
// Output:
// [2 4 3 4]
// [2 4]
}

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

newList := Filter(list, func(nbr int) bool {
return nbr%2 == 0
})

fmt.Printf("%v\n%v", list, newList)
// Output:
// [2 4 3 4]
// [2 4]
}

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

Map(list, func(nbr int) int {
return nbr * 2
})

fmt.Printf("%v", list)
// Output: [2 4 6 8]
}

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

MapI(list, func(nbr int, index int) int {
return nbr * index
})

fmt.Printf("%v", list)
// Output: [0 2 6 12]
}

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

Expand Down
73 changes: 73 additions & 0 deletions mutable/slice_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,79 @@ import (
"github.com/stretchr/testify/assert"
)

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

input1 := []int{1, 2, 3, 4}
r1 := Filter(input1, func(x int) bool {
return x%2 == 0
})

is.Equal(input1, []int{2, 4, 3, 4})
is.Equal(r1, []int{2, 4})

input2 := []string{"", "foo", "", "bar", ""}
r2 := Filter(input2, func(x string) bool {
return len(x) > 0
})

is.Equal(input2, []string{"foo", "bar", "", "bar", ""})
is.Equal(r2, []string{"foo", "bar"})
}

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

r1 := FilterI([]int{1, 2, 3, 4}, func(x int, i int) bool {
is.Equal(i, x-1)
return x%2 == 0
})

is.Equal(r1, []int{2, 4})
}

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

list := []int{1, 2, 3, 4}
Map(list, func(x int) int {
return x * 2
})
is.Equal(len(list), 4)
is.Equal(list, []int{2, 4, 6, 8})

list = []int{1, 2, 3, 4}
Map(list, func(x int) int {
return x * 4
})
is.Equal(len(list), 4)
is.Equal(list, []int{4, 8, 12, 16})
}

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

list := []int{1, 2, 3, 4}
MapI(list, func(x int, index int) int {
is.Equal(index, x-1)
return x * 2
})
is.Equal(len(list), 4)
is.Equal(list, []int{2, 4, 6, 8})

list = []int{1, 2, 3, 4}
MapI(list, func(x int, index int) int {
is.Equal(index, x-1)
return x * 4
})
is.Equal(len(list), 4)
is.Equal(list, []int{4, 8, 12, 16})
}

func TestShuffle(t *testing.T) {
t.Parallel()
is := assert.New(t)
Expand Down
Loading