Go
Latest commit ca3ce1b Jan 13, 2017 @ahmetalpbalkan committed on GitHub travis: check gofmt, capture errors from golint (#62)
golint does not exit with code!=0 on errors, so travis build
will continue with success, therefore using "test -z".

Adding gofmt check.

Signed-off-by: Ahmet Alp Balkan <ahmetalpbalkan@gmail.com>
Permalink
Failed to load latest commit information.
docs Move github site to docs/ Sep 11, 2016
.gitignore v2.0 Aug 29, 2016
.travis.yml travis: check gofmt, capture errors from golint (#62) Jan 13, 2017
LICENSE Update full to license text Sep 12, 2016
README.md Remove v2.0 notice, add versioned go-get (#60) Jan 11, 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/ahmetalpbalkan/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/ahmetalpbalkan/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/ahmetalpbalkan/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/ahmetalpbalkan/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