Skip to content

Commit

Permalink
feat: adding EarliestBy and LatestBy functions (#489)
Browse files Browse the repository at this point in the history
  • Loading branch information
timych authored Jul 13, 2024
1 parent d93dd9a commit 34537d5
Show file tree
Hide file tree
Showing 3 changed files with 136 additions and 0 deletions.
36 changes: 36 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -222,9 +222,11 @@ Supported search helpers:
- [Min](#min)
- [MinBy](#minby)
- [Earliest](#earliest)
- [EarliestBy](#earliestby)
- [Max](#max)
- [MaxBy](#maxby)
- [Latest](#latest)
- [LatestBy](#latestby)
- [First](#first)
- [FirstOrEmpty](#FirstOrEmpty)
- [FirstOr](#FirstOr)
Expand Down Expand Up @@ -2260,6 +2262,23 @@ earliest := lo.Earliest(time.Now(), time.Time{})
// 0001-01-01 00:00:00 +0000 UTC
```

### EarliestBy

Search the minimum time.Time of a collection using the given iteratee function.

Returns zero value when the collection is empty.

```go
type foo struct {
bar time.Time
}

earliest := lo.EarliestBy([]foo{{time.Now()}, {}}, func(i foo) time.Time {
return i.bar
})
// {bar:{2023-04-01 01:02:03 +0000 UTC}}
```

### Max

Search the maximum value of a collection.
Expand Down Expand Up @@ -2308,6 +2327,23 @@ latest := lo.Latest([]time.Time{time.Now(), time.Time{}})
// 2023-04-01 01:02:03 +0000 UTC
```

### LatestBy

Search the maximum time.Time of a collection using the given iteratee function.

Returns zero value when the collection is empty.

```go
type foo struct {
bar time.Time
}

latest := lo.LatestBy([]foo{{time.Now()}, {}}, func(i foo) time.Time {
return i.bar
})
// {bar:{2023-04-01 01:02:03 +0000 UTC}}
```

### First

Returns the first element of a collection and check for availability of the first element.
Expand Down
48 changes: 48 additions & 0 deletions find.go
Original file line number Diff line number Diff line change
Expand Up @@ -286,6 +286,30 @@ func Earliest(times ...time.Time) time.Time {
return min
}

// EarliestBy search the minimum time.Time of a collection using the given iteratee function.
// Returns zero value when the collection is empty.
func EarliestBy[T any](collection []T, iteratee func(item T) time.Time) T {
var earliest T

if len(collection) == 0 {
return earliest
}

earliest = collection[0]
earliestTime := iteratee(collection[0])

for i := 1; i < len(collection); i++ {
itemTime := iteratee(collection[i])

if itemTime.Before(earliestTime) {
earliest = collection[i]
earliestTime = itemTime
}
}

return earliest
}

// Max searches the maximum value of a collection.
// Returns zero value when the collection is empty.
func Max[T constraints.Ordered](collection []T) T {
Expand Down Expand Up @@ -353,6 +377,30 @@ func Latest(times ...time.Time) time.Time {
return max
}

// LatestBy search the maximum time.Time of a collection using the given iteratee function.
// Returns zero value when the collection is empty.
func LatestBy[T any](collection []T, iteratee func(item T) time.Time) T {
var latest T

if len(collection) == 0 {
return latest
}

latest = collection[0]
latestTime := iteratee(collection[0])

for i := 1; i < len(collection); i++ {
itemTime := iteratee(collection[i])

if itemTime.After(latestTime) {
latest = collection[i]
latestTime = itemTime
}
}

return latest
}

// First 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)
Expand Down
52 changes: 52 additions & 0 deletions find_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -336,6 +336,32 @@ func TestEarliest(t *testing.T) {
is.Equal(result2, time.Time{})
}

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

type foo struct {
bar time.Time
}

t1 := time.Now()
t2 := t1.Add(time.Hour)
t3 := t1.Add(-time.Hour)
result1 := EarliestBy([]foo{{t1}, {t2}, {t3}}, func(i foo) time.Time {
return i.bar
})
result2 := EarliestBy([]foo{{t1}}, func(i foo) time.Time {
return i.bar
})
result3 := EarliestBy([]foo{}, func(i foo) time.Time {
return i.bar
})

is.Equal(result1, foo{t3})
is.Equal(result2, foo{t1})
is.Equal(result3, foo{})
}

func TestMax(t *testing.T) {
t.Parallel()
is := assert.New(t)
Expand Down Expand Up @@ -383,6 +409,32 @@ func TestLatest(t *testing.T) {
is.Equal(result2, time.Time{})
}

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

type foo struct {
bar time.Time
}

t1 := time.Now()
t2 := t1.Add(time.Hour)
t3 := t1.Add(-time.Hour)
result1 := LatestBy([]foo{{t1}, {t2}, {t3}}, func(i foo) time.Time {
return i.bar
})
result2 := LatestBy([]foo{{t1}}, func(i foo) time.Time {
return i.bar
})
result3 := LatestBy([]foo{}, func(i foo) time.Time {
return i.bar
})

is.Equal(result1, foo{t2})
is.Equal(result2, foo{t1})
is.Equal(result3, foo{})
}

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

0 comments on commit 34537d5

Please sign in to comment.