Documentation
¶
Overview ¶
Package groupby provides a faithful port of lodash's `groupBy`. It partitions a slice into groups according to a key derived from each element, returning a map from key to the slice of elements that produced it.
Use this package whenever you need to bucket a collection by some computed property: grouping records by category, numbers by parity, strings by length, or structs by a field. It is the Go analogue of the collection helper that lodash exposes as _.groupBy and that many JavaScript and Express codebases rely on for shaping data before rendering or aggregation.
The implementation is a single generic function. GroupBy walks the input slice once, calls the supplied key function on each element, and appends the element to the slice stored under that key. Because iteration proceeds in input order and elements are appended, the order of elements within each group reflects their original order in the input. The overall cost is linear in the length of the slice.
The key function may return any comparable type (its result is constrained by Go's comparable constraint), so keys can be strings, integers, booleans, or any other comparable value including structs of comparable fields. Elements themselves may be of any type. A nil or empty input slice yields an empty but non-nil map, so callers can index or range over the result without a nil check; the returned map is never nil.
Compared to the lodash original, the semantics of grouping and of preserving per-group order are the same, but the Go version is type-safe by construction rather than coercing keys to strings. lodash converts every computed key to a string property name on a plain object, whereas GroupBy keeps the key's native type as the map key, so numeric and boolean keys remain distinct and are not stringified.
Index ¶
Examples ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func GroupBy ¶
func GroupBy[T any, K comparable](s []T, key func(T) K) map[K][]T
GroupBy partitions s into a map keyed by the value returned by key. Each map value is a slice of the elements that produced that key, in the order they appear in s.
A nil or empty input yields an empty (non-nil) map.
Example ¶
ExampleGroupBy partitions a slice of integers into buckets by parity. The key function returns "even" or "odd" for each element, and GroupBy collects the elements that produced each key into a slice. Within every group the elements keep their original input order, so the odd bucket reads 1, 3, 5. Because a returned map has no defined iteration order, this example prints selected keys explicitly rather than ranging over the map. The result map is keyed by the string values the key function returned.
package main
import (
"fmt"
"github.com/malcolmston/express/groupby"
)
func main() {
in := []int{1, 2, 3, 4, 5, 6}
groups := groupby.GroupBy(in, func(n int) string {
if n%2 == 0 {
return "even"
}
return "odd"
})
fmt.Println("odd:", groups["odd"])
fmt.Println("even:", groups["even"])
}
Output: odd: [1 3 5] even: [2 4 6]
Example (Empty) ¶
ExampleGroupBy_empty demonstrates the behavior on empty input. Given a nil slice, GroupBy returns an empty but non-nil map, so callers can safely index or range over the result without a nil check. The length of that map is zero because no elements were grouped. This matches the guarantee that the returned map is never nil. The example prints the length to confirm it is empty.
package main
import (
"fmt"
"github.com/malcolmston/express/groupby"
)
func main() {
groups := groupby.GroupBy([]int(nil), func(n int) int { return n })
fmt.Println(len(groups))
}
Output: 0
Example (Length) ¶
ExampleGroupBy_length groups strings by their length using an integer key. The key function may return any comparable type, and here it returns len(s), so the map is keyed by int. Strings of the same length are gathered together in input order, which is why "one", "two", and "six" share the group for length three. This shows that keys are kept in their native type rather than being stringified. Specific length keys are printed for deterministic output.
package main
import (
"fmt"
"github.com/malcolmston/express/groupby"
)
func main() {
in := []string{"one", "two", "three", "four", "six"}
groups := groupby.GroupBy(in, func(s string) int { return len(s) })
fmt.Println("3:", groups[3])
fmt.Println("4:", groups[4])
fmt.Println("5:", groups[5])
}
Output: 3: [one two six] 4: [four] 5: [three]
Types ¶
This section is empty.