Skip to content

Commit 017eb20

Browse files
committed
feat: add group functions
1 parent 32c7fe9 commit 017eb20

7 files changed

Lines changed: 956 additions & 4 deletions

File tree

README.md

Lines changed: 222 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
# gofn
2-
![Coverage](https://img.shields.io/badge/Coverage-87.7%25-brightgreen)
2+
![Coverage](https://img.shields.io/badge/Coverage-88.7%25-brightgreen)
33
[![Go](https://github.com/devalexandre/gofn/actions/workflows/go.yml/badge.svg)](https://github.com/devalexandre/gofn/actions/workflows/go.yml)
44

55
# library to use golang functional
@@ -31,6 +31,16 @@
3131
- [array.Shift](#arrayshift)
3232
- [array.Sort](#arraysort)
3333
- [array.GroupBy](#arraygroupby)
34+
- [array.GroupSumBy](#arraygroupsumby)
35+
- [array.GroupSumByWhere](#arraygroupsumbywhere)
36+
- [array.GroupCountBy](#arraygroupcountby)
37+
- [array.GroupReduceBy](#arraygroupreduceby)
38+
- [array.GroupStatsBy](#arraygroupstatsby)
39+
- [array.DistinctBy](#arraydistinctby)
40+
- [array.IndexBy](#arrayindexby)
41+
- [array.Partition](#arraypartition)
42+
- [array.SortBy](#arraysortby)
43+
- [array.Take, array.Skip, array.Chunk](#arraytake-arrayskip-arraychunk)
3444
- [chaining functions](#chaining-functions)
3545

3646

@@ -379,6 +389,160 @@ type Itens struct {
379389
fmt.Println(len(grouped)) // 4
380390

381391
```
392+
393+
### array.GroupSumBy
394+
Group items by a key and sum a numeric value for each group.
395+
396+
```go
397+
type Itens struct {
398+
Name string
399+
Price float64
400+
Description string
401+
Qty int
402+
}
403+
404+
itens := []Itens{
405+
{"Item 1", 10.0, "Description 1", 1},
406+
{"Item 2", 20.0, "Description 2", 2},
407+
{"Item 3", 30.0, "Description 3", 3},
408+
{"Item 4", 40.0, "Description 4", 10},
409+
{"Item 4", 40.0, "Description 4", 15},
410+
{"Item 4", 40.0, "Description 4", 25},
411+
}
412+
413+
priceByName := array.GroupSumBy(itens,
414+
func(item Itens) string { return item.Name },
415+
func(item Itens) float64 { return item.Price },
416+
)
417+
418+
qtyByName := array.GroupSumBy(itens,
419+
func(item Itens) string { return item.Name },
420+
func(item Itens) int { return item.Qty },
421+
)
422+
423+
fmt.Println(priceByName["Item 4"]) // 120
424+
fmt.Println(qtyByName["Item 4"]) // 50
425+
```
426+
427+
### array.GroupSumByWhere
428+
Filter, group and sum in one pass.
429+
430+
```go
431+
priceByName := array.GroupSumByWhere(itens,
432+
func(item Itens) bool { return item.Qty > 3 },
433+
func(item Itens) string { return item.Name },
434+
func(item Itens) float64 { return item.Price },
435+
)
436+
437+
fmt.Println(priceByName["Item 4"]) // 120
438+
```
439+
440+
### array.GroupCountBy
441+
Count rows by a key.
442+
443+
```go
444+
countByName := array.GroupCountBy(itens, func(item Itens) string {
445+
return item.Name
446+
})
447+
448+
fmt.Println(countByName["Item 4"]) // 3
449+
```
450+
451+
### array.GroupReduceBy
452+
Build custom summaries by group.
453+
454+
```go
455+
type Summary struct {
456+
TotalPrice float64
457+
TotalQty int
458+
}
459+
460+
summaryByName := array.GroupReduceBy(itens,
461+
func(item Itens) string {
462+
return item.Name
463+
},
464+
func(acc Summary, item Itens) Summary {
465+
acc.TotalPrice += item.Price
466+
acc.TotalQty += item.Qty
467+
return acc
468+
},
469+
)
470+
471+
fmt.Println(summaryByName["Item 4"]) // {120 50}
472+
```
473+
474+
### array.GroupStatsBy
475+
Calculate count, sum, min, max and average by group.
476+
477+
```go
478+
statsByName := array.GroupStatsBy(itens,
479+
func(item Itens) string { return item.Name },
480+
func(item Itens) float64 { return item.Price },
481+
)
482+
483+
fmt.Println(statsByName["Item 4"].Count) // 3
484+
fmt.Println(statsByName["Item 4"].Sum) // 120
485+
fmt.Println(statsByName["Item 4"].Avg) // 40
486+
```
487+
488+
### array.DistinctBy
489+
Keep the first row for each key.
490+
491+
```go
492+
uniqueByName := array.DistinctBy(itens, func(item Itens) string {
493+
return item.Name
494+
})
495+
496+
fmt.Println(len(uniqueByName)) // 4
497+
```
498+
499+
### array.IndexBy
500+
Create a map by key. If a key repeats, the last row wins.
501+
502+
```go
503+
itemByName := array.IndexBy(itens, func(item Itens) string {
504+
return item.Name
505+
})
506+
507+
fmt.Println(itemByName["Item 4"].Qty) // 25
508+
```
509+
510+
### array.Partition
511+
Split rows into matched and unmatched slices.
512+
513+
```go
514+
highQty, lowQty := array.Partition(itens, func(item Itens) bool {
515+
return item.Qty > 3
516+
})
517+
518+
fmt.Println(len(highQty)) // 3
519+
fmt.Println(len(lowQty)) // 3
520+
```
521+
522+
### array.SortBy
523+
Sort rows by a selected field without mutating the original slice.
524+
525+
```go
526+
byQty := array.SortBy(itens, func(item Itens) int {
527+
return item.Qty
528+
})
529+
530+
fmt.Println(byQty[0].Qty) // 1
531+
```
532+
533+
### array.Take, array.Skip, array.Chunk
534+
Use these helpers for pagination and batch processing.
535+
536+
```go
537+
firstPage := array.Take(itens, 2)
538+
nextRows := array.Skip(itens, 2)
539+
batches := array.Chunk(itens, 2)
540+
541+
fmt.Println(len(firstPage)) // 2
542+
fmt.Println(len(nextRows)) // 4
543+
fmt.Println(len(batches)) // 3
544+
```
545+
382546
## chaining functions
383547

384548
You can chain the functions together.
@@ -398,3 +562,60 @@ data := array.Array[int]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
398562
fmt.Println(a) // [4 8 12 16 20]
399563

400564
```
565+
566+
You can also group and sum values after filtering.
567+
568+
```go
569+
type Itens struct {
570+
Name string
571+
Price float64
572+
Description string
573+
Qty int
574+
}
575+
576+
data := array.Array[Itens]{
577+
{"Item 1", 10.0, "Description 1", 1},
578+
{"Item 2", 20.0, "Description 2", 2},
579+
{"Item 3", 30.0, "Description 3", 3},
580+
{"Item 4", 40.0, "Description 4", 10},
581+
{"Item 4", 40.0, "Description 4", 15},
582+
{"Item 4", 40.0, "Description 4", 25},
583+
}
584+
585+
priceByName := data.
586+
Filter(func(item Itens) bool {
587+
return item.Qty > 3
588+
}).
589+
GroupSumBy(
590+
func(item Itens) string { return item.Name },
591+
func(item Itens) float64 { return item.Price },
592+
)
593+
594+
fmt.Println(priceByName["Item 4"]) // 120
595+
```
596+
597+
Some helpers are also available in chain form.
598+
599+
```go
600+
countByName := data.GroupCountBy(func(item Itens) string {
601+
return item.Name
602+
})
603+
604+
statsByName := data.GroupStatsBy(
605+
func(item Itens) string { return item.Name },
606+
func(item Itens) float64 { return item.Price },
607+
)
608+
609+
uniqueByName := data.DistinctBy(func(item Itens) string {
610+
return item.Name
611+
})
612+
613+
highQty, lowQty := data.Partition(func(item Itens) bool {
614+
return item.Qty > 3
615+
})
616+
617+
page := data.
618+
SortByFloat64(func(item Itens) float64 { return item.Price }).
619+
Skip(10).
620+
Take(10)
621+
```

array/array.go

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,3 +61,58 @@ func (a Array[T]) Sort(f func(i, j int) bool) Array[T] {
6161
func (a Array[T]) GroupBy(f func(T) string) map[string][]T {
6262
return GroupBy(a, f)
6363
}
64+
65+
func (a Array[T]) GroupSumBy(key func(T) string, value func(T) float64) map[string]float64 {
66+
return GroupSumBy(a, key, value)
67+
}
68+
69+
func (a Array[T]) GroupSumByWhere(where func(T) bool, key func(T) string, value func(T) float64) map[string]float64 {
70+
return GroupSumByWhere(a, where, key, value)
71+
}
72+
73+
func (a Array[T]) GroupCountBy(key func(T) string) map[string]int {
74+
return GroupCountBy(a, key)
75+
}
76+
77+
func (a Array[T]) GroupStatsBy(key func(T) string, value func(T) float64) map[string]GroupStats[float64] {
78+
return GroupStatsBy(a, key, value)
79+
}
80+
81+
func (a Array[T]) DistinctBy(key func(T) string) Array[T] {
82+
return DistinctBy(a, key)
83+
}
84+
85+
func (a Array[T]) IndexBy(key func(T) string) map[string]T {
86+
return IndexBy(a, key)
87+
}
88+
89+
func (a Array[T]) Partition(f func(T) bool) (Array[T], Array[T]) {
90+
matched, unmatched := Partition(a, f)
91+
return matched, unmatched
92+
}
93+
94+
func (a Array[T]) SortByString(key func(T) string) Array[T] {
95+
return SortBy(a, key)
96+
}
97+
98+
func (a Array[T]) SortByFloat64(key func(T) float64) Array[T] {
99+
return SortBy(a, key)
100+
}
101+
102+
func (a Array[T]) Take(n int) Array[T] {
103+
return Take(a, n)
104+
}
105+
106+
func (a Array[T]) Skip(n int) Array[T] {
107+
return Skip(a, n)
108+
}
109+
110+
func (a Array[T]) Chunk(size int) []Array[T] {
111+
chunks := Chunk(a, size)
112+
result := make([]Array[T], len(chunks))
113+
for i, chunk := range chunks {
114+
result[i] = chunk
115+
}
116+
117+
return result
118+
}

0 commit comments

Comments
 (0)