Skip to content

Commit 34537d5

Browse files
authored
feat: adding EarliestBy and LatestBy functions (samber#489)
1 parent d93dd9a commit 34537d5

File tree

3 files changed

+136
-0
lines changed

3 files changed

+136
-0
lines changed

README.md

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -222,9 +222,11 @@ Supported search helpers:
222222
- [Min](#min)
223223
- [MinBy](#minby)
224224
- [Earliest](#earliest)
225+
- [EarliestBy](#earliestby)
225226
- [Max](#max)
226227
- [MaxBy](#maxby)
227228
- [Latest](#latest)
229+
- [LatestBy](#latestby)
228230
- [First](#first)
229231
- [FirstOrEmpty](#FirstOrEmpty)
230232
- [FirstOr](#FirstOr)
@@ -2260,6 +2262,23 @@ earliest := lo.Earliest(time.Now(), time.Time{})
22602262
// 0001-01-01 00:00:00 +0000 UTC
22612263
```
22622264

2265+
### EarliestBy
2266+
2267+
Search the minimum time.Time of a collection using the given iteratee function.
2268+
2269+
Returns zero value when the collection is empty.
2270+
2271+
```go
2272+
type foo struct {
2273+
bar time.Time
2274+
}
2275+
2276+
earliest := lo.EarliestBy([]foo{{time.Now()}, {}}, func(i foo) time.Time {
2277+
return i.bar
2278+
})
2279+
// {bar:{2023-04-01 01:02:03 +0000 UTC}}
2280+
```
2281+
22632282
### Max
22642283

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

2330+
### LatestBy
2331+
2332+
Search the maximum time.Time of a collection using the given iteratee function.
2333+
2334+
Returns zero value when the collection is empty.
2335+
2336+
```go
2337+
type foo struct {
2338+
bar time.Time
2339+
}
2340+
2341+
latest := lo.LatestBy([]foo{{time.Now()}, {}}, func(i foo) time.Time {
2342+
return i.bar
2343+
})
2344+
// {bar:{2023-04-01 01:02:03 +0000 UTC}}
2345+
```
2346+
23112347
### First
23122348

23132349
Returns the first element of a collection and check for availability of the first element.

find.go

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -286,6 +286,30 @@ func Earliest(times ...time.Time) time.Time {
286286
return min
287287
}
288288

289+
// EarliestBy search the minimum time.Time of a collection using the given iteratee function.
290+
// Returns zero value when the collection is empty.
291+
func EarliestBy[T any](collection []T, iteratee func(item T) time.Time) T {
292+
var earliest T
293+
294+
if len(collection) == 0 {
295+
return earliest
296+
}
297+
298+
earliest = collection[0]
299+
earliestTime := iteratee(collection[0])
300+
301+
for i := 1; i < len(collection); i++ {
302+
itemTime := iteratee(collection[i])
303+
304+
if itemTime.Before(earliestTime) {
305+
earliest = collection[i]
306+
earliestTime = itemTime
307+
}
308+
}
309+
310+
return earliest
311+
}
312+
289313
// Max searches the maximum value of a collection.
290314
// Returns zero value when the collection is empty.
291315
func Max[T constraints.Ordered](collection []T) T {
@@ -353,6 +377,30 @@ func Latest(times ...time.Time) time.Time {
353377
return max
354378
}
355379

380+
// LatestBy search the maximum time.Time of a collection using the given iteratee function.
381+
// Returns zero value when the collection is empty.
382+
func LatestBy[T any](collection []T, iteratee func(item T) time.Time) T {
383+
var latest T
384+
385+
if len(collection) == 0 {
386+
return latest
387+
}
388+
389+
latest = collection[0]
390+
latestTime := iteratee(collection[0])
391+
392+
for i := 1; i < len(collection); i++ {
393+
itemTime := iteratee(collection[i])
394+
395+
if itemTime.After(latestTime) {
396+
latest = collection[i]
397+
latestTime = itemTime
398+
}
399+
}
400+
401+
return latest
402+
}
403+
356404
// First returns the first element of a collection and check for availability of the first element.
357405
func First[T any](collection []T) (T, bool) {
358406
length := len(collection)

find_test.go

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -336,6 +336,32 @@ func TestEarliest(t *testing.T) {
336336
is.Equal(result2, time.Time{})
337337
}
338338

339+
func TestEarliestBy(t *testing.T) {
340+
t.Parallel()
341+
is := assert.New(t)
342+
343+
type foo struct {
344+
bar time.Time
345+
}
346+
347+
t1 := time.Now()
348+
t2 := t1.Add(time.Hour)
349+
t3 := t1.Add(-time.Hour)
350+
result1 := EarliestBy([]foo{{t1}, {t2}, {t3}}, func(i foo) time.Time {
351+
return i.bar
352+
})
353+
result2 := EarliestBy([]foo{{t1}}, func(i foo) time.Time {
354+
return i.bar
355+
})
356+
result3 := EarliestBy([]foo{}, func(i foo) time.Time {
357+
return i.bar
358+
})
359+
360+
is.Equal(result1, foo{t3})
361+
is.Equal(result2, foo{t1})
362+
is.Equal(result3, foo{})
363+
}
364+
339365
func TestMax(t *testing.T) {
340366
t.Parallel()
341367
is := assert.New(t)
@@ -383,6 +409,32 @@ func TestLatest(t *testing.T) {
383409
is.Equal(result2, time.Time{})
384410
}
385411

412+
func TestLatestBy(t *testing.T) {
413+
t.Parallel()
414+
is := assert.New(t)
415+
416+
type foo struct {
417+
bar time.Time
418+
}
419+
420+
t1 := time.Now()
421+
t2 := t1.Add(time.Hour)
422+
t3 := t1.Add(-time.Hour)
423+
result1 := LatestBy([]foo{{t1}, {t2}, {t3}}, func(i foo) time.Time {
424+
return i.bar
425+
})
426+
result2 := LatestBy([]foo{{t1}}, func(i foo) time.Time {
427+
return i.bar
428+
})
429+
result3 := LatestBy([]foo{}, func(i foo) time.Time {
430+
return i.bar
431+
})
432+
433+
is.Equal(result1, foo{t2})
434+
is.Equal(result2, foo{t1})
435+
is.Equal(result3, foo{})
436+
}
437+
386438
func TestFirst(t *testing.T) {
387439
t.Parallel()
388440
is := assert.New(t)

0 commit comments

Comments
 (0)