Documentation
¶
Overview ¶
Package flatten provides faithful ports of lodash's flatten, flattenDeep, and flattenDepth.
The three functions collapse nested slices into a flatter slice. Use Flatten to merge one level of nesting with full compile-time type safety, use FlattenDeep to collapse an arbitrarily nested structure completely, and use FlattenDepth when you need to control exactly how many levels to remove. They are handy for normalizing grouped results, splicing together lists of lists, or unwrapping data that arrived more deeply nested than the consumer wants.
Flatten is generic over the element type and works on a [][]T, concatenating every inner slice into a single []T in order; it is a pure, allocation-sized pass with no reflection. FlattenDeep and FlattenDepth instead accept any and use reflection so they can descend through mixed and heterogeneously typed nesting, including []any, []int, arrays, and interface-wrapped slices. Any element whose dynamic kind is a slice or array is descended into; every other element is appended as a leaf. Interface values are unwrapped to their concrete value before this test, so an []any holding a typed slice is still flattened.
FlattenDeep descends without limit. FlattenDepth takes an explicit depth: depth 1 removes a single level, each larger depth removes one more, and a depth of 0 or any negative value copies the top-level elements without descending at all. A depth larger than the actual nesting simply flattens everything, matching FlattenDeep.
Several edge cases are handled deliberately. Strings are scalar leaves and are never split into runes or bytes, so []any{"hi"} stays a single "hi". A nil, empty, or non-slice input yields an empty but non-nil slice rather than nil, which keeps reflect.DeepEqual comparisons and JSON output predictable. Invalid or nil interface elements are appended as a literal nil. Compared to lodash, these ports drop the iteratee/predicate variants (flatMap and friends) and, because Go slices are homogeneous at the type level, expose the deep and depth forms as any-based functions returning []any while keeping the single-level Flatten fully typed.
Index ¶
Examples ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func Flatten ¶
func Flatten[T any](s [][]T) []T
Flatten flattens s by a single level, concatenating all inner slices into one new slice in order.
A nil or empty input yields an empty (non-nil) slice.
Example ¶
ExampleFlatten merges a single level of nesting with full type safety. Given a [][]int it concatenates every inner slice into one []int, preserving order. This form uses generics rather than reflection, so the element type is checked at compile time and the result keeps that concrete type. Empty inner slices simply contribute nothing. A nil or empty outer slice would yield an empty, non-nil slice.
package main
import (
"fmt"
"github.com/malcolmston/express/flatten"
)
func main() {
got := flatten.Flatten([][]int{{1, 2}, {3, 4}})
fmt.Println(got)
}
Output: [1 2 3 4]
func FlattenDeep ¶
FlattenDeep recursively flattens an arbitrarily nested value into a flat []any. Any element that is itself a slice or array (of any type, including []any) is descended into to unlimited depth; all other elements are appended as leaves.
Strings are treated as scalar leaves and are never flattened into their bytes or runes. A nil or non-slice input yields an empty (non-nil) slice.
Example ¶
ExampleFlattenDeep collapses an arbitrarily nested value all the way down. Because it accepts any and uses reflection, it can descend through mixed nesting such as []any wrapping deeper []any values. Every element whose dynamic kind is a slice or array is flattened; every other element is kept as a leaf. Strings are treated as scalar leaves and are never split into their characters. The heterogeneous nesting here therefore collapses to a single flat sequence of leaves.
package main
import (
"fmt"
"github.com/malcolmston/express/flatten"
)
func main() {
got := flatten.FlattenDeep([]any{1, []any{2, []any{3, []any{4}}}, 5})
fmt.Println(got)
}
Output: [1 2 3 4 5]
func FlattenDepth ¶
FlattenDepth recursively flattens a nested value up to depth levels deep, mirroring lodash's flattenDepth.
FlattenDepth(x, 1) is equivalent to a single-level flatten. A depth of 0 (or negative) copies the top-level elements without descending into any nested slices. Larger depths descend further. Elements that are not slices are always appended as leaves.
Example ¶
ExampleFlattenDepth removes a controlled number of nesting levels. With the same deeply nested input, a depth of 1 removes only the outermost layer, so the inner []any values survive, whereas a depth of 2 removes one more level. A depth of 0 or any negative value copies the top-level elements without descending at all. A depth larger than the actual nesting flattens everything, matching FlattenDeep. The result is a []any because reflection is used to walk the heterogeneous structure.
package main
import (
"fmt"
"github.com/malcolmston/express/flatten"
)
func main() {
nested := []any{1, []any{2, []any{3, []any{4}}}, 5}
fmt.Println(flatten.FlattenDepth(nested, 1))
fmt.Println(flatten.FlattenDepth(nested, 2))
}
Output: [1 2 [3 [4]] 5] [1 2 3 [4] 5]
Types ¶
This section is empty.