From 31351c16de708c76d0bc81e29328c7c25162f44d Mon Sep 17 00:00:00 2001 From: Alireza Kiani Date: Sun, 12 May 2024 03:37:32 +0330 Subject: [PATCH 1/4] feat: add first and firstOrZeroValue functions --- find.go | 24 ++++++++++++++++++++++++ find_test.go | 24 ++++++++++++++++++++++++ 2 files changed, 48 insertions(+) diff --git a/find.go b/find.go index 503bfc89..4fd62a99 100644 --- a/find.go +++ b/find.go @@ -367,6 +367,30 @@ func Last[T any](collection []T) (T, error) { return collection[length-1], nil } +// First returns the first element of a collection or error if empty. +func First[T any](collection []T) (T, error) { + length := len(collection) + + if length == 0 { + var t T + return t, fmt.Errorf("first: cannot extract the first element of an empty slice") + } + + return collection[0], nil +} + +// FirstOrZeroValue returns the first element of a collection or zero value if empty. +func FirstOrZeroValue[T any](collection []T) T { + length := len(collection) + + if length == 0 { + var t T + return t + } + + return collection[0] +} + // 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..ff0898fc 100644 --- a/find_test.go +++ b/find_test.go @@ -372,6 +372,30 @@ 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, err1 := First([]int{1, 2, 3}) + result2, err2 := First([]int{}) + + is.Equal(result1, 1) + is.Equal(err1, nil) + is.Equal(result2, 0) + is.Equal(err2, fmt.Errorf("first: cannot extract the first element of an empty slice")) +} + +func TestFirstOrZeroValue(t *testing.T) { + t.Parallel() + is := assert.New(t) + + result1 := FirstOrZeroValue([]int{1, 2, 3}) + result2 := FirstOrZeroValue([]int{}) + + is.Equal(result1, 1) + is.Equal(result2, 0) +} + func TestNth(t *testing.T) { t.Parallel() is := assert.New(t) From 94555a8c5e8a3d5024564782a2e697765e6dad67 Mon Sep 17 00:00:00 2001 From: Alireza Kiani Date: Sun, 12 May 2024 03:52:07 +0330 Subject: [PATCH 2/4] doc: update readme for First and FirstOrZeroValue functions --- README.md | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/README.md b/README.md index b66a9f65..4b6ef3d3 100644 --- a/README.md +++ b/README.md @@ -223,6 +223,8 @@ Supported search helpers: - [MaxBy](#maxby) - [Latest](#latest) - [Last](#last) +- [First](#first) +- [FirstOrZeroValue](#firstorzerovalue) - [Nth](#nth) - [Sample](#sample) - [Samples](#samples) @@ -2242,6 +2244,25 @@ 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 or error if empty. + +```go +first, err := lo.First([]int{1, 2, 3}) +// 1 +``` +### FirstOrZeroValue + +Returns the first element of a collection or zero value if empty. + +```go +first := lo.FirstOrZeroValue([]int{1, 2, 3}) +// 1 + +first := lo.FirstOrZeroValue([]int{}) +// 0 +``` ### Nth From c7babfaa4607dbd25fb47c540605a664e02e8df6 Mon Sep 17 00:00:00 2001 From: Alireza Kiani Date: Fri, 28 Jun 2024 01:51:20 +0330 Subject: [PATCH 3/4] feat: follow convention for return items and reuse base First function and add FirstOr --- find.go | 26 +++++++++++++++----------- find_test.go | 29 ++++++++++++++++++++++------- 2 files changed, 37 insertions(+), 18 deletions(-) diff --git a/find.go b/find.go index 4fd62a99..58809288 100644 --- a/find.go +++ b/find.go @@ -367,28 +367,32 @@ func Last[T any](collection []T) (T, error) { return collection[length-1], nil } -// First returns the first element of a collection or error if empty. -func First[T any](collection []T) (T, error) { +// First returns the first element of a collection or zero if empty. +func First[T any](collection []T) (T, bool) { length := len(collection) if length == 0 { var t T - return t, fmt.Errorf("first: cannot extract the first element of an empty slice") + return t, false } - return collection[0], nil + return collection[0], true } -// FirstOrZeroValue returns the first element of a collection or zero value if empty. -func FirstOrZeroValue[T any](collection []T) T { - length := len(collection) +// FirstOrEmpty returns the first element of a collection or zero value if empty. +func FirstOrEmpty[T any](collection []T) T { + i, _ := First(collection) + return i +} - if length == 0 { - var t T - return t +// FirstOr returns the first element of a collection or the fallback value that is provided as the second argument. +func FirstOr[T any](collection []T, fallback T) T { + i, ok := First(collection) + if !ok { + return fallback } - return collection[0] + return i } // Nth returns the element at index `nth` of collection. If `nth` is negative, the nth element diff --git a/find_test.go b/find_test.go index ff0898fc..8f9fe325 100644 --- a/find_test.go +++ b/find_test.go @@ -376,24 +376,39 @@ func TestFirst(t *testing.T) { t.Parallel() is := assert.New(t) - result1, err1 := First([]int{1, 2, 3}) - result2, err2 := First([]int{}) + result1, ok1 := First([]int{1, 2, 3}) + result2, ok2 := First([]int{}) is.Equal(result1, 1) - is.Equal(err1, nil) + is.Equal(ok1, true) is.Equal(result2, 0) - is.Equal(err2, fmt.Errorf("first: cannot extract the first element of an empty slice")) + is.Equal(ok2, false) } -func TestFirstOrZeroValue(t *testing.T) { +func TestFirstOrEmpty(t *testing.T) { t.Parallel() is := assert.New(t) - result1 := FirstOrZeroValue([]int{1, 2, 3}) - result2 := FirstOrZeroValue([]int{}) + 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) { From 7159a8c1bc6669635b45e5ab45d1bdf1877c39db Mon Sep 17 00:00:00 2001 From: Alireza Kiani Date: Fri, 28 Jun 2024 01:56:58 +0330 Subject: [PATCH 4/4] doc: update documentation for First methods --- README.md | 29 ++++++++++++++++++++++------- find.go | 6 +++--- 2 files changed, 25 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index 4b6ef3d3..6a15aa41 100644 --- a/README.md +++ b/README.md @@ -224,7 +224,8 @@ Supported search helpers: - [Latest](#latest) - [Last](#last) - [First](#first) -- [FirstOrZeroValue](#firstorzerovalue) +- [FirstOrEmpty](#FirstOrEmpty) +- [FirstOr](#FirstOr) - [Nth](#nth) - [Sample](#sample) - [Samples](#samples) @@ -2246,23 +2247,37 @@ last, err := lo.Last([]int{1, 2, 3}) ``` ### First -Returns the first element of a collection or error if empty. +Returns the first element of a collection and check for availability of the first element. ```go -first, err := lo.First([]int{1, 2, 3}) -// 1 +first, ok := lo.First([]int{1, 2, 3}) +// 1, true + +first, ok := lo.First([]int{}) +// 0, false ``` -### FirstOrZeroValue +### FirstOrEmpty Returns the first element of a collection or zero value if empty. ```go -first := lo.FirstOrZeroValue([]int{1, 2, 3}) +first := lo.FirstOrEmpty([]int{1, 2, 3}) // 1 -first := lo.FirstOrZeroValue([]int{}) +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 58809288..6fc714d5 100644 --- a/find.go +++ b/find.go @@ -367,7 +367,7 @@ func Last[T any](collection []T) (T, error) { return collection[length-1], nil } -// First returns the first element of a collection or zero if empty. +// 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) @@ -379,13 +379,13 @@ func First[T any](collection []T) (T, bool) { return collection[0], true } -// FirstOrEmpty returns the first element of a collection or zero value if empty. +// Returns the first element of a collection or zero value if empty. func FirstOrEmpty[T any](collection []T) T { i, _ := First(collection) return i } -// FirstOr returns the first element of a collection or the fallback value that is provided as the second argument. +// 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 {