.NET LINQ capabilities in Go
Clone or download
golint-fixer and ahmetb Fix golint import path (#75)
I am a bot. Please reach out to [@azillion](https://github.com/azillion) if you have any issues, or just close the PR.
Latest commit 9f6960b Oct 24, 2018
Permalink
Type Name Latest commit message Commit time
Failed to load latest commit information.
.gitignore v2.0 Aug 29, 2016
.travis.yml Fix golint import path (#75) Oct 24, 2018
LICENSE Update full to license text Sep 12, 2016
README.md Fix username in README.md (#66) Feb 26, 2017
aggregate.go Standardize line breaks on method signatures Jan 5, 2017
aggregate_test.go Removed typed files (#47) Dec 14, 2016
benchmark_test.go Generic functions support Dec 8, 2016
compare.go Fix typo, remove trailing newline from examples (#63) Jan 13, 2017
compare_test.go v2.0 Aug 29, 2016
concat.go Godoc cosmetics fixes (#50) Jan 3, 2017
concat_test.go v2.0 Aug 29, 2016
convert.go v2.0 Aug 29, 2016
convert_test.go v2.0 Aug 29, 2016
distinct.go Godoc cosmetics fixes (#50) Jan 3, 2017
distinct_test.go Removed typed files (#47) Dec 14, 2016
doc.go Standardize line breaks on method signatures Jan 5, 2017
example_test.go Fix typo, remove trailing newline from examples (#63) Jan 13, 2017
except.go Standardize line breaks on method signatures Jan 5, 2017
except_test.go Removed typed files (#47) Dec 14, 2016
from.go Godoc cosmetics fixes (#50) Jan 3, 2017
from_test.go v2.0 Aug 29, 2016
general_test.go v2.0 Aug 29, 2016
genericfunc.go Godoc cosmetics fixes (#50) Jan 3, 2017
genericfunc_test.go Removed typed files (#47) Dec 14, 2016
groupby.go Standardize line breaks on method signatures Jan 5, 2017
groupby_test.go Removed typed files (#47) Dec 14, 2016
groupjoin.go Standardize line breaks on method signatures Jan 5, 2017
groupjoin_test.go Removed typed files (#47) Dec 14, 2016
intersect.go Standardize line breaks on method signatures Jan 5, 2017
intersect_test.go Removed typed files (#47) Dec 14, 2016
join.go Standardize line breaks on method signatures Jan 5, 2017
join_test.go Removed typed files (#47) Dec 14, 2016
orderby.go Standardize line breaks on method signatures Jan 5, 2017
orderby_test.go Removed typed files (#47) Dec 14, 2016
result.go ForEach functions (#57) Jan 10, 2017
result_test.go ForEach functions (#57) Jan 10, 2017
reverse.go Godoc cosmetics fixes (#50) Jan 3, 2017
reverse_test.go v2.0 Aug 29, 2016
select.go Godoc cosmetics fixes (#50) Jan 3, 2017
select_test.go Removed typed files (#47) Dec 14, 2016
selectmany.go Standardize line breaks on method signatures Jan 5, 2017
selectmany_test.go Removed typed files (#47) Dec 14, 2016
setup_test.go Removed typed files (#47) Dec 14, 2016
skip.go Godoc cosmetics fixes (#50) Jan 3, 2017
skip_test.go Removed typed files (#47) Dec 14, 2016
take.go Godoc cosmetics fixes (#50) Jan 3, 2017
take_test.go Removed typed files (#47) Dec 14, 2016
union.go Godoc cosmetics fixes (#50) Jan 3, 2017
union_test.go v2.0 Aug 29, 2016
where.go Godoc cosmetics fixes (#50) Jan 3, 2017
where_test.go Removed typed files (#47) Dec 14, 2016
zip.go Standardize line breaks on method signatures Jan 5, 2017
zip_test.go Removed typed files (#47) Dec 14, 2016

README.md

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

go get github.com/ahmetb/go-linq

go-linq follows semantic versioning. However, we recommend using a dependency manager such as govendor or godep to maintain a local copy of this package in your repository. Alternatively you can use the following command to get a specific version:

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

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"
	
type Car struct {
    year int
    owner, model string
}

...


var owners []string

From(cars).Where(func(c interface{}) bool {
	return c.(Car).year >= 2015
}).Select(func(c interface{}) interface{} {
	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

From(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"
	
type Book struct {
	id      int
	title   string
	authors []string
}

author := From(books).SelectMany( // make a flat array of authors
	func(book interface{}) Query {
		return From(book.(Book).authors)
	}).GroupBy( // group by author
	func(author interface{}) interface{} {
		return author // author as key
	}, func(author interface{}) interface{} {
		return author // author as value
	}).OrderByDescending( // sort groups by its length
	func(group interface{}) interface{} {
		return len(group.(Group).Group)
	}).Select( // get authors out of groups
	func(group interface{}) interface{} {
		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() Iterator {
			next := q.Iterate()

			return func() (item interface{}, ok bool) {
				for item, ok = next(); ok; item, ok = next() {
					if item.(int) > threshold {
						return
					}
				}

				return
			}
		},
	}
}

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 interface{}s 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 interface{}) interface{} {...})

you can type:

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

This will make your code free of interface{} 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

From(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)

More examples can be found in the documentation.

Release Notes

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