linq

package
v0.0.0-...-c7ea02f Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Apr 17, 2015 License: Apache-2.0, Apache-2.0 Imports: 3 Imported by: 0

README

go-linq travis-ci status GoDoc Bitdeli Badge

A powerful language integrated query library for Go. Inspired by Microsoft's LINQ.

  • No dependencies: written in vanilla Go!
  • Tested: 100.0% code coverage on all stable releases.
  • Backwards compatibility: Your integration with the library will not be broken except major releases.

Installation

$ go get github.com/ahmetalpbalkan/go-linq

Quick Start

Example query: Find names of students over 18:

import . "github.com/ahmetalpbalkan/go-linq"
	
type Student struct {
    id, age int
    name string
}

over18Names, err := From(students)
	.Where(func (s T) (bool,error){
		return s.(*Student).age >= 18, nil
	})
	.Select(func (s T) (T,error){
		return s.(*Student).name, nil
	}).Results()

Documentation

Here is wiki:

  1. Install & Import
  2. Quickstart (Crash Course)
  3. Parallel LINQ
  4. Table of Query Functions
  5. Remarks & Notes
  6. FAQ

License

This software is distributed under Apache 2.0 License (see LICENSE for more).

Disclaimer

As noted in LICENSE, this library is distributed on an "as is" basis and author's employment association with Microsoft does not imply any sort of warranty or official representation the company. This is purely a personal side project developed on spare times.

Authors

Ahmet Alp Balkan@ahmetalpbalkan

Release Notes


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

Documentation

Overview

Package linq provides methods for querying and manipulating slices and collections.

Author: Ahmet Alp Balkan

Index

Constants

This section is empty.

Variables

View Source
var (
	// ErrNilFunc returned when a predicate, selector or comparer is nil
	ErrNilFunc = errors.New("linq: passed evaluation function is nil")

	// ErrNilInput returned when nil value passed in a slice parameter
	ErrNilInput = errors.New("linq: nil sequence passed as input to function")

	// ErrInvalidInput returned when a non-slice input passed to functions requiring a slice (e.g From, Union, Intersect, Except, Join, GroupJoin)
	ErrInvalidInput = errors.New("linq: non-slice value passed to a T parameter indicating a slice")

	// ErrEmptySequence requested operation is invalid on empty sequences
	ErrEmptySequence = errors.New("linq: empty sequence, operation requires non-empty results sequence")

	// ErrNegativeParam requested when negative value passed to a non-negative requiring parameter
	ErrNegativeParam = errors.New("linq: parameter cannot be negative")

	// ErrNan requested when sequence has invalid elements that method cannot assert into one of builtin numeric types
	ErrNan = errors.New("linq: sequence contains an element of non-numeric types")

	// ErrTypeMismatch returned when sequence nils or elements of different types than function can work with
	ErrTypeMismatch = errors.New("linq: sequence contains element(s) with type different than requested type or nil")

	// ErrNotSingle returned when sequence contains more than one element satisfying the predicate function
	ErrNotSingle = errors.New("linq: sequence contains more than one element matching the given predicate found")
)

Functions

This section is empty.

Types

type ParallelQuery

type ParallelQuery struct {
	// contains filtered or unexported fields
}

ParallelQuery is the type returned from functions executing in parallel. To transform a Query into ParallelQuery, use AsParallel() and use AsSequential() to do vice versa.

func (ParallelQuery) All

func (q ParallelQuery) All(f func(T) (bool, error)) (all bool, err error)

All determines whether all elements of the query source satisfy the provided predicate function by executing the function for each element in parallel.

Returns early if one element does not meet the conditions provided.

Example:

allOver18, err := From(students).AsParallel().All(func (s T)(bool, error){
	return s.(*Person).Age > 18, nil
})

func (ParallelQuery) Any

func (q ParallelQuery) Any() (exists bool, err error)

Any determines whether the query source contains any elements. Example:

anyOver18, err := From(students).AsParallel().Where(func (s T)(bool, error){
	return s.(*Person).Age > 18, nil
}).Any()

func (ParallelQuery) AnyWith

func (q ParallelQuery) AnyWith(f func(T) (bool, error)) (exists bool, err error)

AnyWith determines whether the query source contains any elements satisfying the provided predicate function.

Example:

anyOver18, err := From(students).AsParallel().AnyWith(func (s T)(bool, error){
	return s.(*Person).Age > 18, nil
})

func (ParallelQuery) AsOrdered

func (q ParallelQuery) AsOrdered() (p ParallelQuery)

AsOrdered makes the parallel queries to preserve original order. By default, parallel queries do not preserve the order and process the parallel executions in first-come-first-served fashion.

Not applicable for all query methods and comes with a performance penalty in some queries, please refer to http://msdn.microsoft.com/en-us/library/dd460677(v=vs.110).aspx .

func (ParallelQuery) AsSequential

func (q ParallelQuery) AsSequential() Query

AsSequential returns a Query from the same source and the query functions can be executed in serial for each element of the source sequence. This is for undoing AsParallel().

func (ParallelQuery) AsUnordered

func (q ParallelQuery) AsUnordered() (p ParallelQuery)

AsUnordered undoes the effect of AsOrdered() and do not enforce parallel query to preserve the original order.

See AsOrdered() for remarks.

func (ParallelQuery) Count

func (q ParallelQuery) Count() (count int, err error)

Count returns number of elements in the sequence.

Example:

over18, err := From(students).AsParallel().Where(func (s T)(bool, error){
	return s.(*Person).Age > 18, nil
}).Count()

func (ParallelQuery) CountBy

func (q ParallelQuery) CountBy(f func(T) (bool, error)) (c int, err error)

CountBy returns number of elements satisfying the provided predicate function by running the function for each element of the sequence in parallel.

Example:

over18, err := From(students).AsParallel().CountBy(func (s T)(bool, error){
	return s.(*Person).Age > 18, nil
})

func (ParallelQuery) Results

func (q ParallelQuery) Results() ([]T, error)

Results evaluates the query and returns the results as T slice. An error occurred in during evaluation of the query will be returned.

Example:

results, err := From(slice).AsParallel().Select(something).Results()

func (ParallelQuery) Select

func (q ParallelQuery) Select(f func(T) (T, error)) (r ParallelQuery)

Select projects each element of a sequence into a new form by running the given transform function in parallel for each element. Returns a query with the return values of invoking the transform function on each element of original source.

Example:

names, err := From(animals).AsParallel().Select(func (a T) (T, error){
	return a.(*Animal).Name, nil
}).Results()

func (ParallelQuery) Single

func (q ParallelQuery) Single(f func(T) (bool, error)) (single T, err error)

Single returns the only one element of the original sequence satisfies the provided predicate function if exists, otherwise returns ErrNotSingle. Predicate function is executed in parallel for each element of the sequence. Example:

admin, err := From(students).AsParallel().Single(func (s T)(bool, error){
	return s.(*Person).Id == 1, nil
})
if err == nil {
	// use admin.(*Person)
}

func (ParallelQuery) Where

func (q ParallelQuery) Where(f func(T) (bool, error)) (r ParallelQuery)

Where filters a sequence of values by running given predicate function in parallel for each element.

This function will take elements of the source (or results of previous query) as interface[] so it should make type assertion to work on the types. Returns a query with elements satisfy the condition.

If any of the parallel executions return with an error, this function immediately returns with the error.

If you would like to preserve order from the original sequence, use AsOrdered() on the query beforehand.

Example:

flying, err := From(animals).AsParallel().Where(func (a T) (bool, error){
	return a.(*Animal).IsFlying, nil
}).Results()

type Query

type Query struct {
	// contains filtered or unexported fields
}

Query is the type returned from query functions. To evaluate get the results of the query, use Results().

func From

func From(input T) Query

From initializes a linq query with passed slice as the source. input parameter must be a slice. Otherwise returns ErrInvalidInput in query result evaluating method.

Example:

i := []int{1,2,3,4,5,6}
q := From(i)

Note: Although it looks like a T (interface{}) input, you should pass a slice of any type. There is a hack there to accept any type of slice, which is a workaround of type system of Go.

func Range

func Range(start, count int) (q Query)

Range returns a query with sequence of integral numbers within the specified range. int overflows are not handled.

Example:

seq, err := From(people).Range(-2, 5).Results()
// seq is {-2, -1, 0, 1, 2}

func (Query) All

func (q Query) All(f func(T) (bool, error)) (all bool, err error)

All determines whether all elements of the query source satisfy the provided predicate function.

Returns early if one element does not meet the conditions provided.

Example:

allOver18, err := From(students).All(func (s T)(bool, error){
	return s.(*Person).Age > 18, nil
})

func (Query) Any

func (q Query) Any() (exists bool, err error)

Any determines whether the query source contains any elements.

Example:

anyOver18, err := From(students).Where(func (s T)(bool, error){
	return s.(*Person).Age > 18, nil
}).Any()

func (Query) AnyWith

func (q Query) AnyWith(f func(T) (bool, error)) (exists bool, err error)

AnyWith determines whether the query source contains any elements satisfying the provided predicate function.

Example:

anyOver18, err := From(students).AnyWith(func (s T)(bool, error){
	return s.(*Person).Age > 18, nil
})

func (Query) AsParallel

func (q Query) AsParallel() ParallelQuery

AsParallel returns a ParallelQuery from the same source where the query functions

can be executed in parallel for each element of the source with goroutines.

This is an abstraction to not to break user code. If the query method you are looking for is not available on ParallelQuery, you can go back to serialized Query using AsSequential() method.

func (Query) Average

func (q Query) Average() (avg float64, err error)

Average computes average of numeric values in the original sequence. See golang spec for numeric types. If sequence has non-numeric types or nil, ErrNan is returned. If original sequence is empty, ErrEmptySequence is returned.

This method has a poor performance due to language limitations. On every element, type assertion is made to find the correct type of the element.

Example:

mixedArr = {}interface[]{1, int8(2), uint(3), float64(4.4)}
avg, err := From(mixedArr).Average() // avg is 2.6
// or
avg, err := From([]int{1,2,3,4,5}).Average() // avg is 3.0

func (Query) Count

func (q Query) Count() (count int, err error)

Count returns number of elements in the sequence. Range().

Example:

over18, err := From(students).Where(func (s T)(bool, error){
	return s.(*Person).Age > 18, nil
}).Count()

func (Query) CountBy

func (q Query) CountBy(f func(T) (bool, error)) (c int, err error)

CountBy returns number of elements satisfying the provided predicate function.

Example:

over18, err := From(students).CountBy(func (s T)(bool, error){
	return s.(*Person).Age > 18, nil
})

func (Query) Distinct

func (q Query) Distinct() (r Query)

Distinct returns distinct elements from the provided source using default equality comparer, ==. This is a set operation and returns an unordered sequence.

Example:

distinctInts, err := From(integers).Distinct().Results()

func (Query) DistinctBy

func (q Query) DistinctBy(f func(T, T) (bool, error)) (r Query)

DistinctBy returns distinct elements from the provided source using the provided equality comparer. This is a set operation and returns an unordered sequence. Number of calls to f will be at most N^2 (all elements are distinct) and at best N (all elements are the same).

Example:

distinctFirstNames, err := From(people).DistinctBy(func (p1, p2 T) (bool, error){
	return  p.(*Person).FirstName == p2.(*Person).FirstName, nil
}).Results()

func (Query) ElementAt

func (q Query) ElementAt(i int) (elem T, found bool, err error)

ElementAt returns the element at the specified index i. If i is a negative number ErrNegativeParam, if no element exists at i-th index, found will be returned false.

Example:

second, found, err := From(ints).OrderInts().ElementAt(2)
if err == nil && found {
	// use second.(int)
}

func (Query) Except

func (q Query) Except(inputSlice T) (r Query)

Except returns set difference of the source sequence and the provided input slice using default equality comparer. This is a set operation and returns an unordered sequence. inputSlice must be slice of a type although it looks like T, otherwise returns ErrInvalidInput.

Example: Example:

diffAB, err := From([]int{1,2,3,4,5}).Except([]int{3,4,5,6}).Results()
// diffAB is {1,2}

func (Query) First

func (q Query) First() (elem T, found bool, err error)

First returns the element at first position of the query source if exists. If source is empty or such element is not found, found value will be false, otherwise elem is provided.

Example:

first, found, err := From(ints).OrderInts().First()
if err == nil && found {
	// use first.(int)
}

func (Query) FirstBy

func (q Query) FirstBy(f func(T) (bool, error)) (elem T, found bool, err error)

FirstBy returns the first element in the query source that satisfies the provided predicate. If source is empty or such element is not found, found value will be false, otherwise elem is provided. Example:

second, found, err := From(ints).OrderInts().FirstBy(func (i T)(bool, error){
	return i.(int) % 2 == 0, nil
})
if err == nil && found {
	// use first.(int)
}

func (Query) GroupBy

func (q Query) GroupBy(keySelector func(T) T, valueSelector func(T) T) (map[T][]T, error)

GroupBy returns a map with your specific key and value.

keySelector extracts a key from slice for map key

valueSelector extracts a key from slice for map value

func (Query) GroupJoin

func (q Query) GroupJoin(innerSlice T,
	outerKeySelector func(T) T,
	innerKeySelector func(T) T,
	resultSelector func(
		outer T,
		inners []T) T) (r Query)

GroupJoin correlates the elements of two sequences based on equality of keys and groups the results. The default equality comparer is used to compare keys.

Inner and outer keys are matched using default equality comparer, ==.

Outer collection is the original sequence.

Inner collection is the one provided as innerSlice input parameter as slice of any type. Otherwise returns ErrInvalidInput.

outerKeySelector extracts a key from outer element for comparison.

innerKeySelector extracts a key from outer element for comparison.

resultSelector takes outer element and inner element as inputs and returns a value which will be an element in the resulting query.

func (Query) Intersect

func (q Query) Intersect(inputSlice T) (r Query)

Intersect returns set intersection of the source sequence and the provided input slice using default equality comparer. This is a set operation and may return an unordered sequence. inputSlice must be slice of a type although it looks like T, otherwise returns ErrInvalidInput.

Example:

both, err := From([]int{1,2,3,4,5}).Intersect([]int{3,4,5,6}).Results()
// both is {3,4,5}

func (Query) Join

func (q Query) Join(innerSlice T,
	outerKeySelector func(T) T,
	innerKeySelector func(T) T,
	resultSelector func(
		outer T,
		inner T) T) (r Query)

Join correlates the elements of two sequences based on the equality of keys. Inner and outer keys are matched using default equality comparer, ==.

Outer collection is the original sequence.

Inner collection is the one provided as innerSlice input parameter as slice of any type. Otherwise returns ErrInvalidInput.

outerKeySelector extracts a key from outer element for comparison.

innerKeySelector extracts a key from outer element for comparison.

resultSelector takes outer element and inner element as inputs and returns a value which will be an element in the resulting query.

func (Query) Last

func (q Query) Last() (elem T, found bool, err error)

Last returns the element at last position of the query source if exists. If source is empty or such element is not found, found value will be false, otherwise elem is provided.

Example:

last, found, err := From(ints).OrderInts().Last()
if err == nil && found {
	// use last.(int)
}

func (Query) LastBy

func (q Query) LastBy(f func(T) (bool, error)) (elem T, found bool, err error)

LastBy returns the last element in the query source that satisfies the provided predicate. If source is empty or such element is not found, found value will be false, otherwise elem is provided.

Example:

last, found, err := From(ints).OrderInts().LastBy(func (i T)(bool, error){
	return i.(int) % 2 == 0, nil
})
if err == nil && found {
	// use last.(int)
}

func (Query) MaxFloat64

func (q Query) MaxFloat64() (min float64, err error)

MaxFloat64 returns the element with biggest value in the leftmost of the sequence. Elements of the original sequence should only be float64 or ErrTypeMismatch is returned. If the sequence is empty ErrEmptySequence is returned.

Example:

max, err := From([]float64{1e-9, 2e10, -1e-10, -1}).MaxFloat64() // max is 2e10

func (Query) MaxInt

func (q Query) MaxInt() (min int, err error)

MaxInt returns the element with biggest value in the leftmost of the sequence. Elements of the original sequence should only be int or ErrTypeMismatch is returned. If the sequence is empty ErrEmptySequence is returned.

Example:

max, err := From([]int{1, -100, 10, 0}).MaxInt() // max is 10

func (Query) MaxUint

func (q Query) MaxUint() (min uint, err error)

MaxUint returns the element with biggest value in the leftmost of the sequence. Elements of the original sequence should only be uint or ErrTypeMismatch is returned. If the sequence is empty ErrEmptySequence is returned.

Example:

max, err := From([]uint{1, -100, 10, 0}).MaxUint() // max is 10

func (Query) MinFloat64

func (q Query) MinFloat64() (min float64, err error)

MinFloat64 returns the element with smallest value in the leftmost of the sequence. Elements of the original sequence should only be float64 or ErrTypeMismatch is returned. If the sequence is empty ErrEmptySequence is returned.

Example;

min, err := From([]float64{1e-9, 2e10, -1e-10, -1}).MinFloat64() // min is -1.0

func (Query) MinInt

func (q Query) MinInt() (min int, err error)

MinInt returns the element with smallest value in the leftmost of the sequence. Elements of the original sequence should only be int or ErrTypeMismatch is returned. If the sequence is empty ErrEmptySequence is returned.

Example:

min, err := From([]int{1, -100, 10, 0}).MinInt() // min is -1

func (Query) MinUint

func (q Query) MinUint() (min uint, err error)

MinUint returns the element with smallest value in the leftmost of the sequence. Elements of the original sequence should only be uint or ErrTypeMismatch is returned. If the sequence is empty ErrEmptySequence is returned.

Example:

min, err := From([]uint{1, -100, 10, 0}).MinUint() // min is -1

func (Query) OrderBy

func (q Query) OrderBy(less func(this T, that T) bool) (r Query)

OrderBy returns a new query by sorting elements with provided less function in ascending order. The comparer function should return true if the parameter "this" is less than "that".

Example:

sorted, err := From(people).OrderBy(func (this T, that T) bool {
	return this.(*Person).Age < that.(*Person).Age
}).Results()

func (Query) OrderFloat64s

func (q Query) OrderFloat64s() (r Query)

OrderFloat64s returns a new query by sorting integers in the original sequence in ascending order. Elements of the original sequence should only be float64. Otherwise, ErrTypeMismatch will be returned.

Example:

sorted, err := From([]float64{-1e-9, -1, 1e-9, 1}}).OrderFloat64s().Results()
// sorted = {-1, -1e-9, 1e-9, 1}

func (Query) OrderInts

func (q Query) OrderInts() (r Query)

OrderInts returns a new query by sorting integers in the original sequence in ascending order. Elements of the original sequence should only be int. Otherwise, ErrTypeMismatch will be returned.

Example:

sorted, err := From([]int{6,1,2,-1,10}).OrderInts().Results()
// sorted = {-1, 1, 2, 6, 10}

func (Query) OrderStrings

func (q Query) OrderStrings() (r Query)

OrderStrings returns a new query by sorting integers in the original sequence in ascending order. Elements of the original sequence should only be string. Otherwise, ErrTypeMismatch will be returned.

Example:

sorted, err := From([]string{"foo", "bar", "", "baz"}).OrderStrings().Results()
// sorted = {"", "bar", "baz", "foo"}

func (Query) Results

func (q Query) Results() ([]T, error)

Results evaluates the query and returns the results as T slice. An error occurred in during evaluation of the query will be returned.

Example:

results, err := From(slice).Select(something).Results()

func (Query) Reverse

func (q Query) Reverse() (r Query)

Reverse returns a query with a inverted order of the original source

Example:

reversed, err := From([]int{1,2,3,4,5}).Reverse().Results()

func (Query) Select

func (q Query) Select(f func(T) (T, error)) (r Query)

Select projects each element of a sequence into a new form. Returns a query with the result of invoking the transform function on each element of original source.

Example:

names, err := From(animals).Select(func (a T) (T, error){
	return a.(*Animal).Name, nil
}).Results()

func (Query) Single

func (q Query) Single(f func(T) (bool, error)) (single T, err error)

Single returns the only one element of the original sequence satisfies the provided predicate function if exists, otherwise returns ErrNotSingle.

Example:

admin, err := From(students).Single(func (s T)(bool, error){
	return s.(*Person).Id == 1, nil
})
if err == nil {
	// use admin.(*Person)
}

func (Query) Skip

func (q Query) Skip(n int) (r Query)

Skip returns a new query with nbypassed from the original sequence and takes rest of the elements.

Example:

arr, err := From([]int{1,2,3,4,5}).Skip(3).Results()
if err == nil {
	// arr will be 4, 5
}

func (Query) SkipWhile

func (q Query) SkipWhile(f func(T) (bool, error)) (r Query)

SkipWhile returns a new query with original sequence bypassed as long as a provided predicate is true and then takes the remaining elements.

Example:

arr, err := From([]int{40,10,50,60,100})
	.OrderInts()
	.SkipWhile(func (i T)(bool, error){
		return i.(int) < 50, nil
	}).Results()
if err == nil {
	// arr will be 50, 60, 100
}

func (Query) Sum

func (q Query) Sum() (sum float64, err error)

Sum computes sum of numeric values in the original sequence. See golang spec for numeric types. If sequence has non-numeric types or nil, ErrNan is returned.

This method has a poor performance due to language limitations. On every element, type assertion is made to find the correct type of the element.

Example:

mixedArr = {}interface[]{1, int8(2), uint(3), float64(4.4)}
sum, err := From(mixedArr).Sum() // sum is 10.4
// or
sum, err := From([]int{1,2,3,4,5}).Sum() // sum is 15.0

func (Query) Take

func (q Query) Take(n int) (r Query)

Take returns a new query with n first elements are taken from the original sequence.

Example:

arr, err := From([]int{1,2,3,4,5}).Take(3).Results()
if err == nil {
	// arr will be 1, 2, 3
}

func (Query) TakeWhile

func (q Query) TakeWhile(f func(T) (bool, error)) (r Query)

TakeWhile returns a new query with elements from the original sequence by testing them with provided predicate f and stops taking them first predicate returns false.

Example:

arr, err := From([]int{40,10,50,60,100})
	.OrderInts()
	.TakeWhile(func (i T)(bool, error){
		return i.(int) <= 50, nil
	}).Results()
if err == nil {
	// arr will be 10, 40, 50
}

func (Query) Union

func (q Query) Union(inputSlice T) (r Query)

Union returns set union of the source sequence and the provided input slice using default equality comparer. This is a set operation and returns an unordered sequence. inputSlice must be slice of a type although it looks like T, otherwise returns ErrInvalidInput.

Example:

all, err := From([]int{1,2,3,4,5}).Union([]int{3,4,5,6}).Results()
// all is {1,2,3,4,5,6}

func (Query) Where

func (q Query) Where(f func(T) (bool, error)) (r Query)

Where filters a sequence of values based on a predicate function. This function will take elements of the source (or results of previous query) as interface[] so it should make type assertion to work on the types. Returns a query with elements satisfy the condition.

Example:

flying, err := From(animals).Where(func (a T) (bool, error){
	return a.(*Animal).IsFlying, nil
}).Results()

type T

type T interface{}

T is an alias for interface{} to make your LINQ code shorter.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL