go-linq

repository·master·Indexed 25 days ago

https://github.com/ahmetb/go-linq

A Language Integrated Query (LINQ) library for Go providing lazy evaluation via an iterator pattern. It supports data sources including slices, maps, channels, and strings, offering both standard methods using 'any' and generic typed methods (T-suffix). Key features include data source constructors (FromSlice, FromMap, etc.), aggregation, set operations (Except, Distinct), and support for Go's for...range loops via the Query.Iterate field in v4.

Tokens
7K
Snippets
33
Records
81
Agent score
83%

What's inside go-linq

  1. Quickstart with go-linq

    master

    You can chain methods to perform queries. The basic pattern is: From(data) .Where(predicate) .Select(selector) .Union(data).

    Note that when using standard methods, you must use any and type assertions. For example, to find owners of cars manufactured after 2015:

    import . "github.com/ahmetb/go-linq/v4"
    
    type Car struct {
        year int
        owner, model string
    }
    
    var owners []string
    
    FromSlice(cars).Where(func(c any) bool {
    	return c.(Car).year >= 2015
    }).Select(func(c any) any {
    	return c.(Car).owner
    }).ToSlice(&owners)
  2. Use generic functions (T-suffix methods) for cleaner code

    master

    To avoid any and type assertions, use methods with a T suffix (e.g., WhereT, SelectT). This makes the code more readable but introduces a performance penalty (approximately 5x-10x slower).

    Example using WhereT and SelectT with a Car struct:

    var owners []string
    
    FromSlice(cars).WhereT(func(c Car) bool {
    	return c.year >= 2015
    }).SelectT(func(c Car) string {
    	return c.owner
    }).ToSlice(&owners)
  3. Install go-linq v4

    master

    To use go-linq with Go modules, use the following import path:

    go get github.com/ahmetb/go-linq/v4

    For older versions of Go using different dependency management tools, use:

    go get gopkg.in/ahmetb/go-linq.v4
    go get github.com/ahmetb/go-linq/v4
  4. Iterate over a query using standard Go loops

    master

    In go-linq v4, the Query type exposes an Iterate field of type iter.Seq[any]. This allows you to use the standard Go for ... range loop to iterate over query results.

    q := FromSlice([]int{1, 2, 3, 4})
    
    for v := range q.Iterate {
    	fmt.Println(v)
    }
  5. Create queries using Data Source Constructors

    master

    For better performance and type safety, use the specific From* constructors instead of the generic From function. The From* constructors are optimized for their specific input types and avoid reflection overhead.

    Available constructors:

    • FromSlice: creates a query from a slice
    • FromMap: creates a query from a map
    • FromChannel: creates a query from a channel
    • FromChannelWithContext: creates a query from a channel with Context support
    • FromString: creates a query from a string (iterating over runes)
    • FromIterable: creates a query from a custom collection implementing the Iterable interface
  6. Perform set intersection by key with IntersectBy

    master
    Use IntersectBy(q2 Query, selector func(any) any) to produce a set intersection based on a transformed key. The selector function is invoked on each element of both collections to determine the key used for comparison. This is useful for intersecting collections of complex objects based on a specific property (e.g., an ID).
  7. Use TakeWhileT for typed condition checks

    master

    The TakeWhileT(predicateFn any) method is the typed version of TakeWhile. It accepts a predicate function of type func(TSource) bool.

    Note: TakeWhile has better performance than TakeWhileT.

    func (q Query) TakeWhileT(predicateFn any) Query
  8. Join two collections using Join

    master

    The Join method correlates elements from two collections based on matching keys. It preserves the order of the outer collection and, for each outer element, the order of matching elements in the inner collection. This is a single-call operation that combines two information sources via a common key.

    Parameters:

    • inner: The Query representing the inner collection.
    • outerKeySelector: A function func(any) any that extracts the key from an element in the outer collection.
    • innerKeySelector: A function func(any) any that extracts the key from an element in the inner collection.
    • resultSelector: A function func(outer any, inner any) any that defines how to combine the matched outer and inner elements into a result.
  9. Reduce a collection using Aggregate

    master

    The Aggregate method performs a calculation over a sequence of values. It uses the first element of the source as the initial accumulator value and calls the provided function f(accumulator, item any) any for each subsequent element. If the source is empty, it returns nil.

    func (q Query) Aggregate(f func(accumulator, item any) any) any
  10. Find set difference with Except

    master
    The Except method produces the set difference of two sequences. It returns the members of the first sequence that do not appear in the second sequence. It uses exact equality for comparison.
  11. Flatten collections with index using SelectManyIndexed

    master

    Use SelectManyIndexed to flatten collections while accessing the zero-based index of the element in the source collection. The selector function receives two arguments: index int and outer any.

    func (q Query) SelectManyIndexed(selector func(index int, outer any) Query) Query
  12. Sort collections in ascending order with OrderBy

    master

    Use OrderBy on a Query to sort elements in ascending order based on a key selected by a selector function. The selector function must take an any and return an any representing the sort key.

    For better performance, use the non-generic OrderBy over the typed OrderByT version.

    func (q Query) OrderBy(selector func(any) any) OrderedQuery