diff --git a/README.md b/README.md index ebf3b573..5b96c371 100644 --- a/README.md +++ b/README.md @@ -223,6 +223,9 @@ Supported search helpers: - [MaxBy](#maxby) - [Latest](#latest) - [Last](#last) +- [First](#first) +- [FirstOrEmpty](#FirstOrEmpty) +- [FirstOr](#FirstOr) - [Nth](#nth) - [Sample](#sample) - [Samples](#samples) @@ -2243,6 +2246,39 @@ Returns the last element of a collection or error if empty. last, err := lo.Last([]int{1, 2, 3}) // 3 ``` +### First + +Returns the first element of a collection and check for availability of the first element. + +```go +first, ok := lo.First([]int{1, 2, 3}) +// 1, true + +first, ok := lo.First([]int{}) +// 0, false +``` +### FirstOrEmpty + +Returns the first element of a collection or zero value if empty. + +```go +first := lo.FirstOrEmpty([]int{1, 2, 3}) +// 1 + +first := lo.FirstOrEmpty([]int{}) +// 0 +``` +### FirstOr + +Returns the first element of a collection or the fallback value if empty. + +```go +first := lo.FirstOr([]int{1, 2, 3}, 245) +// 1 + +first := lo.FirstOr([]int{}, 31) +// 31 +``` ### Nth diff --git a/find.go b/find.go index 1d5001a0..542e01d7 100644 --- a/find.go +++ b/find.go @@ -367,6 +367,34 @@ func Last[T any](collection []T) (T, error) { return collection[length-1], nil } +// Returns the first element of a collection and check for availability of the first element. +func First[T any](collection []T) (T, bool) { + length := len(collection) + + if length == 0 { + var t T + return t, false + } + + return collection[0], true +} + +// Returns the first element of a collection or zero value if empty. +func FirstOrEmpty[T any](collection []T) T { + i, _ := First(collection) + return i +} + +// Returns the first element of a collection or the fallback value if empty. +func FirstOr[T any](collection []T, fallback T) T { + i, ok := First(collection) + if !ok { + return fallback + } + + return i +} + // Nth returns the element at index `nth` of collection. If `nth` is negative, the nth element // from the end is returned. An error is returned when nth is out of slice bounds. func Nth[T any, N constraints.Integer](collection []T, nth N) (T, error) { diff --git a/find_test.go b/find_test.go index 04446fb7..8f9fe325 100644 --- a/find_test.go +++ b/find_test.go @@ -372,6 +372,45 @@ func TestLast(t *testing.T) { is.Equal(err2, fmt.Errorf("last: cannot extract the last element of an empty slice")) } +func TestFirst(t *testing.T) { + t.Parallel() + is := assert.New(t) + + result1, ok1 := First([]int{1, 2, 3}) + result2, ok2 := First([]int{}) + + is.Equal(result1, 1) + is.Equal(ok1, true) + is.Equal(result2, 0) + is.Equal(ok2, false) +} + +func TestFirstOrEmpty(t *testing.T) { + t.Parallel() + is := assert.New(t) + + result1 := FirstOrEmpty([]int{1, 2, 3}) + result2 := FirstOrEmpty([]int{}) + result3 := FirstOrEmpty([]string{}) + + is.Equal(result1, 1) + is.Equal(result2, 0) + is.Equal(result3, "") +} + +func TestFirstOr(t *testing.T) { + t.Parallel() + is := assert.New(t) + + result1 := FirstOr([]int{1, 2, 3}, 63) + result2 := FirstOr([]int{}, 23) + result3 := FirstOr([]string{}, "test") + + is.Equal(result1, 1) + is.Equal(result2, 23) + is.Equal(result3, "test") +} + func TestNth(t *testing.T) { t.Parallel() is := assert.New(t)