Skip to content

Commit

Permalink
Add functions: FindEx and FindLastEx
Browse files Browse the repository at this point in the history
  • Loading branch information
tiendc committed Nov 7, 2024
1 parent 1ad9ac4 commit af15ca6
Show file tree
Hide file tree
Showing 3 changed files with 124 additions and 4 deletions.
28 changes: 24 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,8 @@ go get github.com/tiendc/gofn
- [Contain](#contain--containby)
- [ContainAll](#containall)
- [ContainAny](#containany)
- [Find](#find)
- [FindLast](#findlast)
- [Find / FindEx](#find--findex)
- [FindLast / FindLastEx](#findlast--findlastex)
- [IndexOf / IndexOfBy](#indexof--indexofby)
- [LastIndexOf / LastIndexOfBy](#lastindexof--lastindexofby)
- [CountValue / CountValueBy](#countvalue--countvalueby)
Expand Down Expand Up @@ -408,24 +408,44 @@ ContainAny([]int{1, 2, 3, 4, 5}, 2, 4, 7) // true
ContainAny([]int{1, 2, 3, 4, 5}, 7, 8, 9) // false
```

#### Find
#### Find / FindEx

Finds a value in a slice.

```go
v, found := Find([]string{"one", "TWO"}, func(elem string) bool {
return strings.ToLower(elem) == "two"
}) // v == "TWO", found == true

// FindEx lets the given function decide which value to return
type Person struct {
Name string
Age int
}
// Finds age of person having name "Tim"
ageOfTim, found := FindEx([]Person{{"John", 40}, {"Tim", 50}}, func(p Person) (int, bool) {
return p.Age, p.Name == "Tim"
}) // ageOfTim == 50, found == true
```

#### FindLast
#### FindLast / FindLastEx

Finds a value in a slice from the end.

```go
v, found := FindLast([]string{"one", "TWO", "ONe"}, func(elem string) bool {
return strings.ToLower(elem) == "one"
}) // v == "ONe", found == true

// FindLastEx lets the given function decide which value to return
type Person struct {
Name string
Age int
}
// Finds age of the last person having name "tim"
ageOfTim, found := FindLastEx([]Person{{"John", 40}, {"Tim", 50}, {"TIM", 60}}, func(p Person) (int, bool) {
return p.Age, strings.ToLower(p.Name) == "tim"
}) // ageOfTim == 60, found == true
```

#### IndexOf / IndexOfBy
Expand Down
20 changes: 20 additions & 0 deletions slice.go
Original file line number Diff line number Diff line change
Expand Up @@ -290,6 +290,16 @@ func FindPredPtr[T any, S ~[]T](a S, pred func(t *T) bool) (t T, found bool) {
return FindPtr(a, pred)
}

// FindEx finds value in slice with returning value decided by the given function
func FindEx[T any, V any, S ~[]T](a S, pred func(t T) (V, bool)) (v V, found bool) {
for i := range a {
if v, ok := pred(a[i]); ok {
return v, true
}
}
return v, false
}

// FindLast finds value in slice from the end by predicate
func FindLast[T any, S ~[]T](a S, pred func(t T) bool) (t T, found bool) {
for i := len(a) - 1; i >= 0; i-- {
Expand Down Expand Up @@ -320,6 +330,16 @@ func FindLastPredPtr[T any, S ~[]T](a S, pred func(t *T) bool) (t T, found bool)
return FindLastPtr(a, pred)
}

// FindLastEx finds value in slice from the end with returning value decided by the given function
func FindLastEx[T any, V any, S ~[]T](a S, pred func(t T) (V, bool)) (v V, found bool) {
for i := len(a) - 1; i >= 0; i-- {
if v, ok := pred(a[i]); ok {
return v, true
}
}
return v, false
}

// IndexOf gets index of item in slice.
// Returns -1 if not found.
func IndexOf[T comparable, S ~[]T](a S, t T) int {
Expand Down
80 changes: 80 additions & 0 deletions slice_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -461,6 +461,45 @@ func Test_FindPredPtr_Deprecated(t *testing.T) {
assert.Equal(t, 2, v2)
}

func Test_FindEx(t *testing.T) {
_, found := FindEx([]any{}, func(i any) (any, bool) { return i, i == 1 })
assert.False(t, found)
_, found = FindEx([]any{"one"}, func(i any) (any, bool) { return i, i == "One" })
assert.False(t, found)
_, found = FindEx([]any{"one", "two"}, func(i any) (any, bool) { return i, i == "" })
assert.False(t, found)
_, found = FindEx([]any{1, 2, 3}, func(i any) (any, bool) { return i, i == 4 })
assert.False(t, found)
_, found = FindEx([]any{1.1, 2.2, 3.3}, func(i any) (any, bool) { return i, i == 3.35 })
assert.False(t, found)

type St struct {
Key string
Val int
}
_, found = FindEx([]St{{"k1", 11}, {"k2", 22}, {"k3", 33}},
func(i St) (int, bool) { return i.Val, i.Key == "k4" })
assert.False(t, found)

v1, found := FindEx([]any{1}, func(i any) (any, bool) { return i, i == 1 })
assert.True(t, found)
assert.Equal(t, 1, v1)
v2, found := FindEx([]any{1, 2, 3, 1, 2, 3}, func(i any) (any, bool) { return i, i == 2 })
assert.True(t, found)
assert.Equal(t, 2, v2)
v3, found := FindEx([]any{"one", "two"}, func(i any) (any, bool) { return i, i == "two" })
assert.True(t, found)
assert.Equal(t, "two", v3)
v4, found := FindEx([]any{St{"k1", 11}, St{"k2", 22}, St{"k3", 33}},
func(i any) (int, bool) { ii := i.(St); return ii.Val, ii.Key == "k3" })
assert.True(t, found)
assert.Equal(t, 33, v4)
v5, found := FindEx([]St{{"k1", 11}, {"k2", 22}, {"k2", 33}},
func(i St) (int, bool) { return i.Val, i.Key == "k2" })
assert.True(t, found)
assert.Equal(t, 22, v5)
}

func Test_FindLast(t *testing.T) {
_, found := FindLast([]any{}, func(i any) bool { return i == 1 })
assert.False(t, found)
Expand Down Expand Up @@ -561,6 +600,47 @@ func Test_FindLastPredPtr(t *testing.T) {
assert.Equal(t, 2, v2)
}

func Test_FindLastEx(t *testing.T) {
_, found := FindLastEx([]any{}, func(i any) (any, bool) { return i, i == 1 })
assert.False(t, found)
_, found = FindLastEx([]any{"one"}, func(i any) (any, bool) { return i, i == "One" })
assert.False(t, found)
_, found = FindLastEx([]any{"one", "two"}, func(i any) (any, bool) { return i, i == "" })
assert.False(t, found)
_, found = FindLastEx([]any{1, 2, 3}, func(i any) (any, bool) { return i, i == 4 })
assert.False(t, found)
_, found = FindLastEx([]any{1.1, 2.2, 3.3}, func(i any) (any, bool) { return i, i == 3.35 })
assert.False(t, found)

type St struct {
Key string
Val int
}
_, found = FindLastEx([]St{{"k1", 11}, {"k2", 22}, {"k3", 33}},
func(i St) (int, bool) { return i.Val, i.Key == "k4" })
assert.False(t, found)

v1, found := FindLastEx([]any{1}, func(i any) (any, bool) { return i, i == 1 })
assert.True(t, found)
assert.Equal(t, 1, v1)
v2, found := FindLastEx([]any{1, 2, 3, 1, 2, 3}, func(i any) (any, bool) { return i, i == 2 })
assert.True(t, found)
assert.Equal(t, 2, v2)
v3, found := FindLastEx([]any{"one", "two"}, func(i any) (any, bool) { return i, i == "two" })
assert.True(t, found)
assert.Equal(t, "two", v3)
v4, found := FindLastEx([]any{"one", "", "two", ""}, func(i any) (any, bool) { return i, i == "" })
assert.True(t, found)
assert.Equal(t, "", v4)
v5, found := FindLastEx([]any{1.1, 1.1, 2.2, 3.3}, func(i any) (any, bool) { return i, i == 1.1 })
assert.True(t, found)
assert.Equal(t, 1.1, v5)
v6, found := FindLastEx([]St{{"k1", 11}, {"k2", 22}, {"k2", 33}},
func(i St) (int, bool) { return i.Val, i.Key == "k2" })
assert.True(t, found)
assert.Equal(t, 33, v6)
}

func Test_IndexOf(t *testing.T) {
assert.Equal(t, -1, IndexOf([]int{}, 1))
assert.Equal(t, -1, IndexOf([]string{"one"}, "One"))
Expand Down

0 comments on commit af15ca6

Please sign in to comment.