MCPcopy Index your code
hub / github.com/ahmetb/go-linq

github.com/ahmetb/go-linq @v4.0.0 sqlite

repository ↗ · DeepWiki ↗ · release v4.0.0 ↗ · + Follow
422 symbols 2,065 edges 53 files 234 documented · 55%
README

go-linq GoDoc Build Status Coverage Status Go Report Card

A powerful language integrated query (LINQ) library for Go.

  • Written in vanilla Go, no dependencies!
  • Complete lazy evaluation with iterator pattern
  • Safe for concurrent use
  • Supports generic functions to make your code cleaner and free of type assertions
  • Supports arrays, slices, maps, strings, channels and custom collections

Installation

When used with Go modules, use the following import path:

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

Older versions of Go using different dependency management tools can use the following import path to prevent breaking API changes:

go get gopkg.in/ahmetb/go-linq.v4

Quickstart

Usage is as easy as chaining methods like:

From(slice) .Where(predicate) .Select(selector) .Union(data)

Example 1: Find all 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)

Or, you can use generic functions, like WhereT and SelectT to simplify your code (at a performance penalty):

var owners []string

FromSlice(cars).WhereT(func(c Car) bool {
    return c.year >= 2015
}).SelectT(func(c Car) string {
    return c.owner
}).ToSlice(&owners)

Example 2: Find the author who has written the most books

import . "github.com/ahmetb/go-linq/v4"

type Book struct {
    id      int
    title   string
    authors []string
}

author := FromSlice(books).SelectMany( // make a flat array of authors
    func(book any) Query {
        return From(book.(Book).authors)
    }).GroupBy( // group by author
    func(author any) any {
        return author // author as key
    }, func(author any) any {
        return author // author as value
    }).OrderByDescending( // sort groups by its length
    func(group any) any {
        return len(group.(Group).Group)
    }).Select( // get authors out of groups
    func(group any) any {
        return group.(Group).Key
    }).First() // take the first author

Example 3: Implement a custom method that leaves only values greater than the specified threshold

type MyQuery Query

func (q MyQuery) GreaterThan(threshold int) Query {
    return Query{
        Iterate: func(yield func(any) bool) {
            q.Iterate(func(item any) bool {
                if item.(int) > threshold {
                    return yield(item)
                }
                return true
            })
        },
    }
}

result := MyQuery(Range(1,10)).GreaterThan(5).Results()

Generic Functions

Although Go doesn't implement generics, with some reflection tricks, you can use go-linq without typing anys and type assertions. This will introduce a performance penalty (5x-10x slower) but will yield in a cleaner and more readable code.

Methods with T suffix (such as WhereT) accept functions with generic types. So instead of

.Select(func(v any) any {...})

you can type:

.SelectT(func(v YourType) YourOtherType {...})

This will make your code free of any and type assertions.

Example 4: "MapReduce" in a slice of string sentences to list the top 5 most used words using generic functions

var results []string

FromSlice(sentences).
    // split sentences to words
    SelectManyT(func(sentence string) Query {
        return From(strings.Split(sentence, " "))
    }).
    // group the words
    GroupByT(
        func(word string) string { return word },
        func(word string) string { return word },
    ).
    // order by count
    OrderByDescendingT(func(wordGroup Group) int {
        return len(wordGroup.Group)
    }).
    // order by the word
    ThenByT(func(wordGroup Group) string {
        return wordGroup.Key.(string)
    }).
    Take(5).  // take the top 5
    // project the words using the index as rank
    SelectIndexedT(func(index int, wordGroup Group) string {
        return fmt.Sprintf("Rank: #%d, Word: %s, Counts: %d", index+1, wordGroup.Key, len(wordGroup.Group))
    }).
    ToSlice(&results)

Manual Iteration

Since go-linq v4 manual iteration follows Go’s standard iterator pattern introduced with the iter package. The Query type exposes an Iterate field of type iter.Seq[any], making it easier to integrate with Go’s native iteration style.

Example 5: Iterate over a query using the standard for ... range loop

q := FromSlice([]int{1, 2, 3, 4})

for v := range q.Iterate {
    fmt.Println(v)
}

More examples can be found in the documentation.

Data Source Constructors

Since go-linq v4, a new family of constructor functions provides a type-safe and efficient way to create queries from various data sources. Each function is optimized for its specific input type, avoiding the overhead of reflection.

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

The older From function remains available for backward compatibility, but it relies on runtime reflection and is significantly less efficient. For all new code, it’s recommended to use the explicit From* constructors.

Release Notes

v4.0.0 (2025-10-12)
* Breaking change: Migrated to standard Go iterator pattern. (thanks @kalaninja!)
* Added typed constructors: FromSlice(), FromMap(), FromChannel(),
 FromChannelWithContext(), FromString().
* Breaking change: Removed FromChannelT() in favor of FromChannel().

v3.2.0 (2020-12-29)
* Added FromChannelT().
* Added DefaultIfEmpty().

v3.1.0 (2019-07-09)
* Support for Go modules
* Added IndexOf()/IndexOfT().

v3.0.0 (2017-01-10)
* Breaking change: ToSlice() now overwrites existing slice starting
  from index 0 and grows/reslices it as needed.
* Generic methods support (thanks @cleitonmarx!)
  - Accepting parametrized functions was originally proposed in #26
  - You can now avoid type assertions and interface{}s
  - Functions with generic methods are named as "MethodNameT" and
    signature for the existing LINQ methods are unchanged.
* Added ForEach(), ForEachIndexed() and AggregateWithSeedBy().

v2.0.0 (2016-09-02)
* IMPORTANT: This release is a BREAKING CHANGE. The old version
  is archived at the 'archive/0.9' branch or the 0.9 tags.
* A COMPLETE REWRITE of go-linq with better performance and memory
  efficiency. (thanks @kalaninja!)
* API has significantly changed. Most notably:
  - linq.T removed in favor of interface{}
  - library methods no longer return errors
  - PLINQ removed for now (see channels support)
  - support for channels, custom collections and comparables

v0.9-rc4
* GroupBy()

v0.9-rc3.2
* bugfix: All() iterating over values instead of indices

v0.9-rc3.1
* bugfix: modifying result slice affects subsequent query methods

v0.9-rc3
* removed FirstOrNil, LastOrNil, ElementAtOrNil methods

v0.9-rc2.5
* slice-accepting methods accept slices of any type with reflections

v0.9-rc2
* parallel linq (plinq) implemented
* Queryable separated into Query & ParallelQuery
* fixed early termination for All

v0.9-rc1
* many linq methods are implemented
* methods have error handling support
* type assertion limitations are unresolved
* travis-ci.org build integrated
* open sourced on github, master & dev branches

Extension points exported contracts — how you extend this code

Iterable (Interface)
Iterable is an interface that has to be implemented by a custom collection to work with linq. [1 implementers]
from.go
Comparable (Interface)
Comparable is an interface that has to be implemented by a custom type to work with linq. Example: func (f foo) Compa [1 …
compare.go

Core symbols most depended-on inside this repo

From
called by 283
from.go
newElemTypeSlice
called by 107
genericfunc.go
ToSlice
called by 64
result.go
simpleParamValidator
called by 57
genericfunc.go
newGenericFunc
called by 48
genericfunc.go
Call
called by 47
genericfunc.go
Iterate
called by 37
from.go
Range
called by 18
from.go

Shape

Function 282
Method 115
Struct 17
FuncType 4
Interface 2
TypeAlias 2

Languages

Go100%

Modules by API surface

example_test.go119 symbols
result_test.go42 symbols
result.go36 symbols
orderby.go18 symbols
orderby_test.go14 symbols
from_test.go13 symbols
from.go13 symbols
selectmany_test.go10 symbols
setup_test.go8 symbols
selectmany.go8 symbols
genericfunc.go8 symbols
aggregate_test.go7 symbols

For agents

$ claude mcp add go-linq \
  -- python -m otcore.mcp_server <graph>

⬇ download graph artifact