Skip to content

Commit c7a67ca

Browse files
authored
feat(mutable): adding Map, MapI, Filter, FilterI (#577)
* feat(mutable): adding Map, MapI, Filter, FilterI * Update README.md * doc: add doc and examples for lom.Filter * oops
1 parent e5dba6f commit c7a67ca

File tree

4 files changed

+199
-0
lines changed

4 files changed

+199
-0
lines changed

README.md

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ You can import `lo` using:
4949
import (
5050
"github.com/samber/lo"
5151
lop "github.com/samber/lo/parallel"
52+
lom "github.com/samber/lo/mutable"
5253
)
5354
```
5455

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

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

348+
Mutable: like `lo.Filter()`, but the slice is updated in place.
349+
350+
```go
351+
import lom "github.com/samber/lo/mutable"
352+
353+
list := []int{1, 2, 3, 4}
354+
newList := lom.Filter(list, func(x int) bool {
355+
return x%2 == 0
356+
})
357+
358+
list
359+
// []int{2, 4, 3, 4}
360+
361+
newList
362+
// []int{2, 4}
363+
```
364+
347365
### Map
348366

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

391+
Mutable: like `lo.Map()`, but the slice is updated in place.
392+
393+
```go
394+
import lom "github.com/samber/lo/mutable"
395+
396+
list := []int{1, 2, 3, 4}
397+
lom.Map(list, func(x int) int {
398+
return i*2
399+
})
400+
// []int{2, 4, 6, 8}
401+
```
402+
373403
### UniqMap
374404

375405
Manipulates a slice and transforms it to a slice of another type with unique values.

mutable/slice.go

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,54 @@ package mutable
22

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

5+
// Filter is a generic function that modifies the input slice in-place to contain only the elements
6+
// that satisfy the provided predicate function. The predicate function takes an element of the slice and its index,
7+
// and should return true for elements that should be kept and false for elements that should be removed.
8+
// The function returns the modified slice, which may be shorter than the original if some elements were removed.
9+
// Note that the order of elements in the original slice is preserved in the output.
10+
func Filter[T any, Slice ~[]T](collection Slice, predicate func(item T) bool) Slice {
11+
j := 0
12+
for _, item := range collection {
13+
if predicate(item) {
14+
collection[j] = item
15+
j++
16+
}
17+
}
18+
return collection[:j]
19+
}
20+
21+
// FilterI is a generic function that modifies the input slice in-place to contain only the elements
22+
// that satisfy the provided predicate function. The predicate function takes an element of the slice and its index,
23+
// and should return true for elements that should be kept and false for elements that should be removed.
24+
// The function returns the modified slice, which may be shorter than the original if some elements were removed.
25+
// Note that the order of elements in the original slice is preserved in the output.
26+
func FilterI[T any, Slice ~[]T](collection Slice, predicate func(item T, index int) bool) Slice {
27+
j := 0
28+
for i, item := range collection {
29+
if predicate(item, i) {
30+
collection[j] = item
31+
j++
32+
}
33+
}
34+
return collection[:j]
35+
}
36+
37+
// Map is a generic function that modifies the input slice in-place to contain the result of applying the provided
38+
// function to each element of the slice. The function returns the modified slice, which has the same length as the original.
39+
func Map[T any, Slice ~[]T](collection Slice, fn func(item T) T) {
40+
for i := range collection {
41+
collection[i] = fn(collection[i])
42+
}
43+
}
44+
45+
// MapI is a generic function that modifies the input slice in-place to contain the result of applying the provided
46+
// function to each element of the slice. The function returns the modified slice, which has the same length as the original.
47+
func MapI[T any, Slice ~[]T](collection Slice, fn func(item T, index int) T) {
48+
for i := range collection {
49+
collection[i] = fn(collection[i], i)
50+
}
51+
}
52+
553
// Shuffle returns an array of shuffled values. Uses the Fisher-Yates shuffle algorithm.
654
// Play: https://go.dev/play/p/2xb3WdLjeSJ
755
func Shuffle[T any, Slice ~[]T](collection Slice) {

mutable/slice_example_test.go

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,54 @@ package mutable
22

33
import "fmt"
44

5+
func ExampleFilter() {
6+
list := []int{1, 2, 3, 4}
7+
8+
newList := Filter(list, func(nbr int) bool {
9+
return nbr%2 == 0
10+
})
11+
12+
fmt.Printf("%v\n%v", list, newList)
13+
// Output:
14+
// [2 4 3 4]
15+
// [2 4]
16+
}
17+
18+
func ExampleFilterI() {
19+
list := []int{1, 2, 3, 4}
20+
21+
newList := Filter(list, func(nbr int) bool {
22+
return nbr%2 == 0
23+
})
24+
25+
fmt.Printf("%v\n%v", list, newList)
26+
// Output:
27+
// [2 4 3 4]
28+
// [2 4]
29+
}
30+
31+
func ExampleMap() {
32+
list := []int{1, 2, 3, 4}
33+
34+
Map(list, func(nbr int) int {
35+
return nbr * 2
36+
})
37+
38+
fmt.Printf("%v", list)
39+
// Output: [2 4 6 8]
40+
}
41+
42+
func ExampleMapI() {
43+
list := []int{1, 2, 3, 4}
44+
45+
MapI(list, func(nbr int, index int) int {
46+
return nbr * index
47+
})
48+
49+
fmt.Printf("%v", list)
50+
// Output: [0 2 6 12]
51+
}
52+
553
func ExampleShuffle() {
654
list := []int{0, 1, 2, 3, 4, 5}
755

mutable/slice_test.go

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,79 @@ import (
66
"github.com/stretchr/testify/assert"
77
)
88

9+
func TestFilter(t *testing.T) {
10+
t.Parallel()
11+
is := assert.New(t)
12+
13+
input1 := []int{1, 2, 3, 4}
14+
r1 := Filter(input1, func(x int) bool {
15+
return x%2 == 0
16+
})
17+
18+
is.Equal(input1, []int{2, 4, 3, 4})
19+
is.Equal(r1, []int{2, 4})
20+
21+
input2 := []string{"", "foo", "", "bar", ""}
22+
r2 := Filter(input2, func(x string) bool {
23+
return len(x) > 0
24+
})
25+
26+
is.Equal(input2, []string{"foo", "bar", "", "bar", ""})
27+
is.Equal(r2, []string{"foo", "bar"})
28+
}
29+
30+
func TestFilterI(t *testing.T) {
31+
t.Parallel()
32+
is := assert.New(t)
33+
34+
r1 := FilterI([]int{1, 2, 3, 4}, func(x int, i int) bool {
35+
is.Equal(i, x-1)
36+
return x%2 == 0
37+
})
38+
39+
is.Equal(r1, []int{2, 4})
40+
}
41+
42+
func TestMap(t *testing.T) {
43+
t.Parallel()
44+
is := assert.New(t)
45+
46+
list := []int{1, 2, 3, 4}
47+
Map(list, func(x int) int {
48+
return x * 2
49+
})
50+
is.Equal(len(list), 4)
51+
is.Equal(list, []int{2, 4, 6, 8})
52+
53+
list = []int{1, 2, 3, 4}
54+
Map(list, func(x int) int {
55+
return x * 4
56+
})
57+
is.Equal(len(list), 4)
58+
is.Equal(list, []int{4, 8, 12, 16})
59+
}
60+
61+
func TestMapI(t *testing.T) {
62+
t.Parallel()
63+
is := assert.New(t)
64+
65+
list := []int{1, 2, 3, 4}
66+
MapI(list, func(x int, index int) int {
67+
is.Equal(index, x-1)
68+
return x * 2
69+
})
70+
is.Equal(len(list), 4)
71+
is.Equal(list, []int{2, 4, 6, 8})
72+
73+
list = []int{1, 2, 3, 4}
74+
MapI(list, func(x int, index int) int {
75+
is.Equal(index, x-1)
76+
return x * 4
77+
})
78+
is.Equal(len(list), 4)
79+
is.Equal(list, []int{4, 8, 12, 16})
80+
}
81+
982
func TestShuffle(t *testing.T) {
1083
t.Parallel()
1184
is := assert.New(t)

0 commit comments

Comments
 (0)