feat(Go-Tool):2020/11/12:新增linq包使用示例(未完成)
This commit is contained in:
+29
@@ -0,0 +1,29 @@
|
||||
# Compiled Object files, Static and Dynamic libs (Shared Objects)
|
||||
*.o
|
||||
*.a
|
||||
*.so
|
||||
|
||||
# Folders
|
||||
_obj
|
||||
_test
|
||||
|
||||
# Architecture specific extensions/prefixes
|
||||
*.[568vq]
|
||||
[568vq].out
|
||||
|
||||
*.cgo1.go
|
||||
*.cgo2.c
|
||||
_cgo_defun.c
|
||||
_cgo_gotypes.go
|
||||
_cgo_export.*
|
||||
|
||||
_testmain.go
|
||||
|
||||
*.exe
|
||||
*.test
|
||||
*.prof
|
||||
|
||||
### Code ###
|
||||
# Visual Studio Code - https://code.visualstudio.com/
|
||||
.settings/
|
||||
.vscode/
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
sudo: false
|
||||
|
||||
language: go
|
||||
go:
|
||||
- 1.5
|
||||
- 1.7
|
||||
|
||||
before_install:
|
||||
- go get github.com/mattn/goveralls
|
||||
- go get golang.org/x/tools/cmd/cover
|
||||
- go get -u github.com/golang/lint/golint
|
||||
|
||||
script:
|
||||
- go vet -x ./...
|
||||
- golint ./...
|
||||
- go test -v ./...
|
||||
- go test -covermode=count -coverprofile=profile.cov
|
||||
|
||||
after_script:
|
||||
- goveralls -coverprofile=profile.cov -service=travis-ci
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
Copyright 2016 Ahmet Alp Balkan
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
+141
@@ -0,0 +1,141 @@
|
||||
# go-linq [](https://godoc.org/github.com/ahmetalpbalkan/go-linq) [](https://travis-ci.org/ahmetalpbalkan/go-linq) [](https://coveralls.io/github/ahmetalpbalkan/go-linq?branch=master) [](https://goreportcard.com/report/github.com/ahmetalpbalkan/go-linq)
|
||||
A powerful language integrated query (LINQ) library for Go.
|
||||
* Written in vanilla Go!
|
||||
* Safe for concurrent use
|
||||
* Complete lazy evaluation with iterator pattern
|
||||
* Supports arrays, slices, maps, strings, channels and custom collections
|
||||
(collection needs to implement `Iterable` interface and element - `Comparable`
|
||||
interface)
|
||||
|
||||
## Installation
|
||||
|
||||
$ go get github.com/ahmetalpbalkan/go-linq
|
||||
|
||||
> :warning: :warning: `go-linq` has recently introduced _breaking API changes_
|
||||
> with v2.0.0. See [release notes](#release-notes) for details. v2.0.0 comes with
|
||||
> a refined interface, dramatically increased performance and memory efficiency,
|
||||
> and new features such as lazy evaluation ([read more](http://kalan.rocks/2016/07/16/manipulating-data-with-iterators-in-go/)).
|
||||
>
|
||||
> The old version is still available in `archive/0.9` branch and tagged as `0.9`
|
||||
> as well. If you are using `go-linq`, please vendor a copy of it in your
|
||||
> source tree to avoid getting broken by upstream changes.
|
||||
|
||||
## Quickstart
|
||||
|
||||
Usage is as easy as chaining methods like:
|
||||
|
||||
`From(slice)` `.Where(predicate)` `.Select(selector)` `.Union(data)`
|
||||
|
||||
**Example: Find all owners of cars manufactured from 2015**
|
||||
```go
|
||||
import . "github.com/ahmetalpbalkan/go-linq"
|
||||
|
||||
type Car struct {
|
||||
id, year int
|
||||
owner, model string
|
||||
}
|
||||
|
||||
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)
|
||||
```
|
||||
|
||||
**Example: Find the author who has written the most books**
|
||||
```go
|
||||
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: Implement a custom method that leaves only values greater than the specified threshold**
|
||||
```go
|
||||
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()
|
||||
```
|
||||
|
||||
**More examples** can be found in [documentation](https://godoc.org/github.com/ahmetalpbalkan/go-linq).
|
||||
|
||||
## Release Notes
|
||||
~~~
|
||||
|
||||
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
|
||||
~~~
|
||||
+53
@@ -0,0 +1,53 @@
|
||||
package linq
|
||||
|
||||
// Aggregate applies an accumulator function over a sequence.
|
||||
//
|
||||
// Aggregate method makes it simple to perform a calculation over a sequence of values.
|
||||
// This method works by calling f() one time for each element in source
|
||||
// except the first one. Each time f() is called, Aggregate passes both
|
||||
// the element from the sequence and an aggregated value (as the first argument to f()).
|
||||
// The first element of source is used as the initial aggregate value.
|
||||
// The result of f() replaces the previous aggregated value.
|
||||
//
|
||||
// Aggregate returns the final result of f().
|
||||
func (q Query) Aggregate(
|
||||
f func(interface{}, interface{}) interface{}) interface{} {
|
||||
next := q.Iterate()
|
||||
|
||||
result, any := next()
|
||||
if !any {
|
||||
return nil
|
||||
}
|
||||
|
||||
for current, ok := next(); ok; current, ok = next() {
|
||||
result = f(result, current)
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
// AggregateWithSeed applies an accumulator function over a sequence.
|
||||
// The specified seed value is used as the initial accumulator value.
|
||||
//
|
||||
// Aggregate method makes it simple to perform a calculation over a sequence of values.
|
||||
// This method works by calling f() one time for each element in source
|
||||
// except the first one. Each time f() is called, Aggregate passes both
|
||||
// the element from the sequence and an aggregated value (as the first argument to f()).
|
||||
// The value of the seed parameter is used as the initial aggregate value.
|
||||
// The result of f() replaces the previous aggregated value.
|
||||
//
|
||||
// Aggregate returns the final result of f().
|
||||
func (q Query) AggregateWithSeed(
|
||||
seed interface{},
|
||||
f func(interface{}, interface{}) interface{},
|
||||
) interface{} {
|
||||
|
||||
next := q.Iterate()
|
||||
result := seed
|
||||
|
||||
for current, ok := next(); ok; current, ok = next() {
|
||||
result = f(result, current)
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
+200
@@ -0,0 +1,200 @@
|
||||
package linq
|
||||
|
||||
type comparer func(interface{}, interface{}) int
|
||||
|
||||
// Comparable is an interface that has to be implemented by a
|
||||
// custom collection elememts in order to work with linq.
|
||||
//
|
||||
// Example:
|
||||
// func (f foo) CompareTo(c Comparable) int {
|
||||
// a, b := f.f1, c.(foo).f1
|
||||
//
|
||||
// if a < b {
|
||||
// return -1
|
||||
// } else if a > b {
|
||||
// return 1
|
||||
// }
|
||||
//
|
||||
// return 0
|
||||
// }
|
||||
type Comparable interface {
|
||||
CompareTo(Comparable) int
|
||||
}
|
||||
|
||||
func getComparer(data interface{}) comparer {
|
||||
switch data.(type) {
|
||||
case int:
|
||||
return func(x, y interface{}) int {
|
||||
a, b := x.(int), y.(int)
|
||||
switch {
|
||||
case a > b:
|
||||
return 1
|
||||
case b > a:
|
||||
return -1
|
||||
default:
|
||||
return 0
|
||||
}
|
||||
}
|
||||
case int8:
|
||||
return func(x, y interface{}) int {
|
||||
a, b := x.(int8), y.(int8)
|
||||
switch {
|
||||
case a > b:
|
||||
return 1
|
||||
case b > a:
|
||||
return -1
|
||||
default:
|
||||
return 0
|
||||
}
|
||||
}
|
||||
case int16:
|
||||
return func(x, y interface{}) int {
|
||||
a, b := x.(int16), y.(int16)
|
||||
switch {
|
||||
case a > b:
|
||||
return 1
|
||||
case b > a:
|
||||
return -1
|
||||
default:
|
||||
return 0
|
||||
}
|
||||
}
|
||||
case int32:
|
||||
return func(x, y interface{}) int {
|
||||
a, b := x.(int32), y.(int32)
|
||||
switch {
|
||||
case a > b:
|
||||
return 1
|
||||
case b > a:
|
||||
return -1
|
||||
default:
|
||||
return 0
|
||||
}
|
||||
}
|
||||
case int64:
|
||||
return func(x, y interface{}) int {
|
||||
a, b := x.(int64), y.(int64)
|
||||
switch {
|
||||
case a > b:
|
||||
return 1
|
||||
case b > a:
|
||||
return -1
|
||||
default:
|
||||
return 0
|
||||
}
|
||||
}
|
||||
case uint:
|
||||
return func(x, y interface{}) int {
|
||||
a, b := x.(uint), y.(uint)
|
||||
switch {
|
||||
case a > b:
|
||||
return 1
|
||||
case b > a:
|
||||
return -1
|
||||
default:
|
||||
return 0
|
||||
}
|
||||
}
|
||||
case uint8:
|
||||
return func(x, y interface{}) int {
|
||||
a, b := x.(uint8), y.(uint8)
|
||||
switch {
|
||||
case a > b:
|
||||
return 1
|
||||
case b > a:
|
||||
return -1
|
||||
default:
|
||||
return 0
|
||||
}
|
||||
}
|
||||
case uint16:
|
||||
return func(x, y interface{}) int {
|
||||
a, b := x.(uint16), y.(uint16)
|
||||
switch {
|
||||
case a > b:
|
||||
return 1
|
||||
case b > a:
|
||||
return -1
|
||||
default:
|
||||
return 0
|
||||
}
|
||||
}
|
||||
case uint32:
|
||||
return func(x, y interface{}) int {
|
||||
a, b := x.(uint32), y.(uint32)
|
||||
switch {
|
||||
case a > b:
|
||||
return 1
|
||||
case b > a:
|
||||
return -1
|
||||
default:
|
||||
return 0
|
||||
}
|
||||
}
|
||||
case uint64:
|
||||
return func(x, y interface{}) int {
|
||||
a, b := x.(uint64), y.(uint64)
|
||||
switch {
|
||||
case a > b:
|
||||
return 1
|
||||
case b > a:
|
||||
return -1
|
||||
default:
|
||||
return 0
|
||||
}
|
||||
}
|
||||
case float32:
|
||||
return func(x, y interface{}) int {
|
||||
a, b := x.(float32), y.(float32)
|
||||
switch {
|
||||
case a > b:
|
||||
return 1
|
||||
case b > a:
|
||||
return -1
|
||||
default:
|
||||
return 0
|
||||
}
|
||||
}
|
||||
case float64:
|
||||
return func(x, y interface{}) int {
|
||||
a, b := x.(float64), y.(float64)
|
||||
switch {
|
||||
case a > b:
|
||||
return 1
|
||||
case b > a:
|
||||
return -1
|
||||
default:
|
||||
return 0
|
||||
}
|
||||
}
|
||||
case string:
|
||||
return func(x, y interface{}) int {
|
||||
a, b := x.(string), y.(string)
|
||||
switch {
|
||||
case a > b:
|
||||
return 1
|
||||
case b > a:
|
||||
return -1
|
||||
default:
|
||||
return 0
|
||||
}
|
||||
}
|
||||
case bool:
|
||||
return func(x, y interface{}) int {
|
||||
a, b := x.(bool), y.(bool)
|
||||
switch {
|
||||
case a == b:
|
||||
return 0
|
||||
case a:
|
||||
return 1
|
||||
default:
|
||||
return -1
|
||||
}
|
||||
}
|
||||
default:
|
||||
return func(x, y interface{}) int {
|
||||
a, b := x.(Comparable), y.(Comparable)
|
||||
return a.CompareTo(b)
|
||||
}
|
||||
}
|
||||
}
|
||||
+74
@@ -0,0 +1,74 @@
|
||||
package linq
|
||||
|
||||
// Append inserts an item to the end of a collection,
|
||||
// so it becomes the last item.
|
||||
func (q Query) Append(item interface{}) Query {
|
||||
return Query{
|
||||
Iterate: func() Iterator {
|
||||
next := q.Iterate()
|
||||
appended := false
|
||||
|
||||
return func() (interface{}, bool) {
|
||||
i, ok := next()
|
||||
if ok {
|
||||
return i, ok
|
||||
}
|
||||
|
||||
if !appended {
|
||||
appended = true
|
||||
return item, true
|
||||
}
|
||||
|
||||
return nil, false
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// Concat concatenates two collections.
|
||||
//
|
||||
// The Concat method differs from the Union method because the Concat method
|
||||
// returns all the original elements in the input sequences.
|
||||
// The Union method returns only unique elements.
|
||||
func (q Query) Concat(q2 Query) Query {
|
||||
return Query{
|
||||
Iterate: func() Iterator {
|
||||
next := q.Iterate()
|
||||
next2 := q2.Iterate()
|
||||
use1 := true
|
||||
|
||||
return func() (item interface{}, ok bool) {
|
||||
if use1 {
|
||||
item, ok = next()
|
||||
if ok {
|
||||
return
|
||||
}
|
||||
|
||||
use1 = false
|
||||
}
|
||||
|
||||
return next2()
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// Prepend inserts an item to the beginning of a collection,
|
||||
// so it becomes the first item.
|
||||
func (q Query) Prepend(item interface{}) Query {
|
||||
return Query{
|
||||
Iterate: func() Iterator {
|
||||
next := q.Iterate()
|
||||
prepended := false
|
||||
|
||||
return func() (interface{}, bool) {
|
||||
if prepended {
|
||||
return next()
|
||||
}
|
||||
|
||||
prepended = true
|
||||
return item, true
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
+70
@@ -0,0 +1,70 @@
|
||||
package linq
|
||||
|
||||
type intConverter func(interface{}) int64
|
||||
|
||||
func getIntConverter(data interface{}) intConverter {
|
||||
switch data.(type) {
|
||||
case (int):
|
||||
return func(i interface{}) int64 {
|
||||
return int64(i.(int))
|
||||
}
|
||||
case (int8):
|
||||
return func(i interface{}) int64 {
|
||||
return int64(i.(int8))
|
||||
}
|
||||
case (int16):
|
||||
return func(i interface{}) int64 {
|
||||
return int64(i.(int16))
|
||||
}
|
||||
case (int32):
|
||||
return func(i interface{}) int64 {
|
||||
return int64(i.(int32))
|
||||
}
|
||||
}
|
||||
|
||||
return func(i interface{}) int64 {
|
||||
return i.(int64)
|
||||
}
|
||||
}
|
||||
|
||||
type uintConverter func(interface{}) uint64
|
||||
|
||||
func getUIntConverter(data interface{}) uintConverter {
|
||||
switch data.(type) {
|
||||
case (uint):
|
||||
return func(i interface{}) uint64 {
|
||||
return uint64(i.(uint))
|
||||
}
|
||||
case (uint8):
|
||||
return func(i interface{}) uint64 {
|
||||
return uint64(i.(uint8))
|
||||
}
|
||||
case (uint16):
|
||||
return func(i interface{}) uint64 {
|
||||
return uint64(i.(uint16))
|
||||
}
|
||||
case (uint32):
|
||||
return func(i interface{}) uint64 {
|
||||
return uint64(i.(uint32))
|
||||
}
|
||||
}
|
||||
|
||||
return func(i interface{}) uint64 {
|
||||
return i.(uint64)
|
||||
}
|
||||
}
|
||||
|
||||
type floatConverter func(interface{}) float64
|
||||
|
||||
func getFloatConverter(data interface{}) floatConverter {
|
||||
switch data.(type) {
|
||||
case (float32):
|
||||
return func(i interface{}) float64 {
|
||||
return float64(i.(float32))
|
||||
}
|
||||
}
|
||||
|
||||
return func(i interface{}) float64 {
|
||||
return i.(float64)
|
||||
}
|
||||
}
|
||||
+75
@@ -0,0 +1,75 @@
|
||||
package linq
|
||||
|
||||
// Distinct method returns distinct elements from a collection.
|
||||
// The result is an unordered collection that contains no duplicate values.
|
||||
func (q Query) Distinct() Query {
|
||||
return Query{
|
||||
Iterate: func() Iterator {
|
||||
next := q.Iterate()
|
||||
set := make(map[interface{}]bool)
|
||||
|
||||
return func() (item interface{}, ok bool) {
|
||||
for item, ok = next(); ok; item, ok = next() {
|
||||
if _, has := set[item]; !has {
|
||||
set[item] = true
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// Distinct method returns distinct elements from a collection.
|
||||
// The result is an ordered collection that contains no duplicate values.
|
||||
//
|
||||
// NOTE: Distinct method on OrderedQuery type has better performance than
|
||||
// Distinct method on Query type
|
||||
func (oq OrderedQuery) Distinct() OrderedQuery {
|
||||
return OrderedQuery{
|
||||
orders: oq.orders,
|
||||
Query: Query{
|
||||
Iterate: func() Iterator {
|
||||
next := oq.Iterate()
|
||||
var prev interface{}
|
||||
|
||||
return func() (item interface{}, ok bool) {
|
||||
for item, ok = next(); ok; item, ok = next() {
|
||||
if item != prev {
|
||||
prev = item
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// DistinctBy method returns distinct elements from a collection. This method
|
||||
// executes selector function for each element to determine a value to compare.
|
||||
// The result is an unordered collection that contains no duplicate values.
|
||||
func (q Query) DistinctBy(selector func(interface{}) interface{}) Query {
|
||||
return Query{
|
||||
Iterate: func() Iterator {
|
||||
next := q.Iterate()
|
||||
set := make(map[interface{}]bool)
|
||||
|
||||
return func() (item interface{}, ok bool) {
|
||||
for item, ok = next(); ok; item, ok = next() {
|
||||
s := selector(item)
|
||||
if _, has := set[s]; !has {
|
||||
set[s] = true
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
// Package linq provides methods for querying and manipulating
|
||||
// slices, arrays, maps, strings, channels and collections.
|
||||
//
|
||||
// Authors: Alexander Kalankhodzhaev (kalan), Ahmet Alp Balkan
|
||||
package linq
|
||||
+59
@@ -0,0 +1,59 @@
|
||||
package linq
|
||||
|
||||
// Except produces the set difference of two sequences.
|
||||
// The set difference is the members of the first sequence
|
||||
// that don't appear in the second sequence.
|
||||
func (q Query) Except(q2 Query) Query {
|
||||
return Query{
|
||||
Iterate: func() Iterator {
|
||||
next := q.Iterate()
|
||||
|
||||
next2 := q2.Iterate()
|
||||
set := make(map[interface{}]bool)
|
||||
for i, ok := next2(); ok; i, ok = next2() {
|
||||
set[i] = true
|
||||
}
|
||||
|
||||
return func() (item interface{}, ok bool) {
|
||||
for item, ok = next(); ok; item, ok = next() {
|
||||
if _, has := set[item]; !has {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// ExceptBy invokes a transform function on each element of a collection
|
||||
// and produces the set difference of two sequences.
|
||||
// The set difference is the members of the first sequence
|
||||
// that don't appear in the second sequence.
|
||||
func (q Query) ExceptBy(
|
||||
q2 Query, selector func(interface{}) interface{}) Query {
|
||||
return Query{
|
||||
Iterate: func() Iterator {
|
||||
next := q.Iterate()
|
||||
|
||||
next2 := q2.Iterate()
|
||||
set := make(map[interface{}]bool)
|
||||
for i, ok := next2(); ok; i, ok = next2() {
|
||||
s := selector(i)
|
||||
set[s] = true
|
||||
}
|
||||
|
||||
return func() (item interface{}, ok bool) {
|
||||
for item, ok = next(); ok; item, ok = next() {
|
||||
s := selector(item)
|
||||
if _, has := set[s]; !has {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
+172
@@ -0,0 +1,172 @@
|
||||
package linq
|
||||
|
||||
import "reflect"
|
||||
|
||||
// Iterator is an alias for function to iterate over data.
|
||||
type Iterator func() (item interface{}, ok bool)
|
||||
|
||||
// Query is the type returned from query functions.
|
||||
// It can be iterated manually as shown in the example.
|
||||
type Query struct {
|
||||
Iterate func() Iterator
|
||||
}
|
||||
|
||||
// KeyValue is a type that is used to iterate over a map
|
||||
// (if query is created from a map). This type is also used by
|
||||
// ToMap() method to output result of a query into a map.
|
||||
type KeyValue struct {
|
||||
Key interface{}
|
||||
Value interface{}
|
||||
}
|
||||
|
||||
// Iterable is an interface that has to be implemented by a
|
||||
// custom collection in order to work with linq.
|
||||
type Iterable interface {
|
||||
Iterate() Iterator
|
||||
}
|
||||
|
||||
// From initializes a linq query with passed slice, array or map
|
||||
// as the source. String, channel or struct implementing Iterable
|
||||
// interface can be used as an input. In this case From delegates it
|
||||
// to FromString, FromChannel and FromIterable internally.
|
||||
func From(source interface{}) Query {
|
||||
src := reflect.ValueOf(source)
|
||||
|
||||
switch src.Kind() {
|
||||
case reflect.Slice, reflect.Array:
|
||||
len := src.Len()
|
||||
|
||||
return Query{
|
||||
Iterate: func() Iterator {
|
||||
index := 0
|
||||
|
||||
return func() (item interface{}, ok bool) {
|
||||
ok = index < len
|
||||
if ok {
|
||||
item = src.Index(index).Interface()
|
||||
index++
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
},
|
||||
}
|
||||
case reflect.Map:
|
||||
len := src.Len()
|
||||
|
||||
return Query{
|
||||
Iterate: func() Iterator {
|
||||
index := 0
|
||||
keys := src.MapKeys()
|
||||
|
||||
return func() (item interface{}, ok bool) {
|
||||
ok = index < len
|
||||
if ok {
|
||||
key := keys[index]
|
||||
item = KeyValue{
|
||||
Key: key.Interface(),
|
||||
Value: src.MapIndex(key).Interface(),
|
||||
}
|
||||
|
||||
index++
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
},
|
||||
}
|
||||
case reflect.String:
|
||||
return FromString(source.(string))
|
||||
case reflect.Chan:
|
||||
return FromChannel(source.(chan interface{}))
|
||||
default:
|
||||
return FromIterable(source.(Iterable))
|
||||
}
|
||||
}
|
||||
|
||||
// FromChannel initializes a linq query with passed channel,
|
||||
// linq iterates over channel until it is closed.
|
||||
func FromChannel(source <-chan interface{}) Query {
|
||||
return Query{
|
||||
Iterate: func() Iterator {
|
||||
return func() (item interface{}, ok bool) {
|
||||
item, ok = <-source
|
||||
return
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// FromString initializes a linq query with passed string,
|
||||
// linq iterates over runes of string.
|
||||
func FromString(source string) Query {
|
||||
runes := []rune(source)
|
||||
len := len(runes)
|
||||
|
||||
return Query{
|
||||
Iterate: func() Iterator {
|
||||
index := 0
|
||||
|
||||
return func() (item interface{}, ok bool) {
|
||||
ok = index < len
|
||||
if ok {
|
||||
item = runes[index]
|
||||
index++
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// FromIterable initializes a linq query with custom collection passed.
|
||||
// This collection has to implement Iterable interface, linq iterates over items,
|
||||
// that has to implement Comparable interface or be basic types.
|
||||
func FromIterable(source Iterable) Query {
|
||||
return Query{
|
||||
Iterate: source.Iterate,
|
||||
}
|
||||
}
|
||||
|
||||
// Range generates a sequence of integral numbers within a specified range.
|
||||
func Range(start, count int) Query {
|
||||
return Query{
|
||||
Iterate: func() Iterator {
|
||||
index := 0
|
||||
current := start
|
||||
|
||||
return func() (item interface{}, ok bool) {
|
||||
if index >= count {
|
||||
return nil, false
|
||||
}
|
||||
|
||||
item, ok = current, true
|
||||
|
||||
index++
|
||||
current++
|
||||
return
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// Repeat generates a sequence that contains one repeated value.
|
||||
func Repeat(value interface{}, count int) Query {
|
||||
return Query{
|
||||
Iterate: func() Iterator {
|
||||
index := 0
|
||||
|
||||
return func() (item interface{}, ok bool) {
|
||||
if index >= count {
|
||||
return nil, false
|
||||
}
|
||||
|
||||
item, ok = value, true
|
||||
|
||||
index++
|
||||
return
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
+48
@@ -0,0 +1,48 @@
|
||||
package linq
|
||||
|
||||
// Group is a type that is used to store the result of GroupBy method.
|
||||
type Group struct {
|
||||
Key interface{}
|
||||
Group []interface{}
|
||||
}
|
||||
|
||||
// GroupBy method groups the elements of a collection according
|
||||
// to a specified key selector function and projects the elements for each group
|
||||
// by using a specified function.
|
||||
func (q Query) GroupBy(
|
||||
keySelector func(interface{}) interface{},
|
||||
elementSelector func(interface{}) interface{},
|
||||
) Query {
|
||||
|
||||
return Query{
|
||||
func() Iterator {
|
||||
next := q.Iterate()
|
||||
set := make(map[interface{}][]interface{})
|
||||
|
||||
for item, ok := next(); ok; item, ok = next() {
|
||||
key := keySelector(item)
|
||||
set[key] = append(set[key], elementSelector(item))
|
||||
}
|
||||
|
||||
len := len(set)
|
||||
idx := 0
|
||||
groups := make([]Group, len)
|
||||
for k, v := range set {
|
||||
groups[idx] = Group{k, v}
|
||||
idx++
|
||||
}
|
||||
|
||||
index := 0
|
||||
|
||||
return func() (item interface{}, ok bool) {
|
||||
ok = index < len
|
||||
if ok {
|
||||
item = groups[index]
|
||||
index++
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
+50
@@ -0,0 +1,50 @@
|
||||
package linq
|
||||
|
||||
// GroupJoin correlates the elements of two collections based on key equality,
|
||||
// and groups the results.
|
||||
//
|
||||
// This method produces hierarchical results, which means that elements from outer query
|
||||
// are paired with collections of matching elements from inner. GroupJoin enables you
|
||||
// to base your results on a whole set of matches for each element of outer query.
|
||||
//
|
||||
// The resultSelector function is called only one time for each outer element
|
||||
// together with a collection of all the inner elements that match the outer element.
|
||||
// This differs from the Join method, in which the result selector function is invoked
|
||||
// on pairs that contain one element from outer and one element from inner.
|
||||
//
|
||||
// GroupJoin preserves the order of the elements of outer, and for each element of outer,
|
||||
// the order of the matching elements from inner.
|
||||
func (q Query) GroupJoin(
|
||||
inner Query,
|
||||
outerKeySelector func(interface{}) interface{},
|
||||
innerKeySelector func(interface{}) interface{},
|
||||
resultSelector func(outer interface{}, inners []interface{}) interface{},
|
||||
) Query {
|
||||
|
||||
return Query{
|
||||
Iterate: func() Iterator {
|
||||
outernext := q.Iterate()
|
||||
innernext := inner.Iterate()
|
||||
|
||||
innerLookup := make(map[interface{}][]interface{})
|
||||
for innerItem, ok := innernext(); ok; innerItem, ok = innernext() {
|
||||
innerKey := innerKeySelector(innerItem)
|
||||
innerLookup[innerKey] = append(innerLookup[innerKey], innerItem)
|
||||
}
|
||||
|
||||
return func() (item interface{}, ok bool) {
|
||||
if item, ok = outernext(); !ok {
|
||||
return
|
||||
}
|
||||
|
||||
if group, has := innerLookup[outerKeySelector(item)]; !has {
|
||||
item = resultSelector(item, []interface{}{})
|
||||
} else {
|
||||
item = resultSelector(item, group)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
+67
@@ -0,0 +1,67 @@
|
||||
package linq
|
||||
|
||||
// Intersect produces the set intersection of the source collection and the
|
||||
// provided input collection. The intersection of two sets A and B is defined as
|
||||
// the set that contains all the elements of A that also appear in B,
|
||||
// but no other elements.
|
||||
func (q Query) Intersect(q2 Query) Query {
|
||||
return Query{
|
||||
Iterate: func() Iterator {
|
||||
next := q.Iterate()
|
||||
next2 := q2.Iterate()
|
||||
|
||||
set := make(map[interface{}]bool)
|
||||
for item, ok := next2(); ok; item, ok = next2() {
|
||||
set[item] = true
|
||||
}
|
||||
|
||||
return func() (item interface{}, ok bool) {
|
||||
for item, ok = next(); ok; item, ok = next() {
|
||||
if _, has := set[item]; has {
|
||||
delete(set, item)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// IntersectBy produces the set intersection of the source collection and the
|
||||
// provided input collection. The intersection of two sets A and B is defined as
|
||||
// the set that contains all the elements of A that also appear in B,
|
||||
// but no other elements.
|
||||
//
|
||||
// IntersectBy invokes a transform function on each element of both collections.
|
||||
func (q Query) IntersectBy(
|
||||
q2 Query,
|
||||
selector func(interface{}) interface{},
|
||||
) Query {
|
||||
|
||||
return Query{
|
||||
Iterate: func() Iterator {
|
||||
next := q.Iterate()
|
||||
next2 := q2.Iterate()
|
||||
|
||||
set := make(map[interface{}]bool)
|
||||
for item, ok := next2(); ok; item, ok = next2() {
|
||||
s := selector(item)
|
||||
set[s] = true
|
||||
}
|
||||
|
||||
return func() (item interface{}, ok bool) {
|
||||
for item, ok = next(); ok; item, ok = next() {
|
||||
s := selector(item)
|
||||
if _, has := set[s]; has {
|
||||
delete(set, s)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
+56
@@ -0,0 +1,56 @@
|
||||
package linq
|
||||
|
||||
// Join correlates the elements of two collection based on matching keys.
|
||||
//
|
||||
// A join refers to the operation of correlating the elements of two sources
|
||||
// of information based on a common key. Join brings the two information sources
|
||||
// and the keys by which they are matched together in one method call.
|
||||
// This differs from the use of SelectMany, which requires more than one method call
|
||||
// to perform the same operation.
|
||||
//
|
||||
// Join preserves the order of the elements of outer collection,
|
||||
// and for each of these elements, the order of the matching elements of inner.
|
||||
func (q Query) Join(
|
||||
inner Query,
|
||||
outerKeySelector func(interface{}) interface{},
|
||||
innerKeySelector func(interface{}) interface{},
|
||||
resultSelector func(outer interface{}, inner interface{}) interface{},
|
||||
) Query {
|
||||
|
||||
return Query{
|
||||
Iterate: func() Iterator {
|
||||
outernext := q.Iterate()
|
||||
innernext := inner.Iterate()
|
||||
|
||||
innerLookup := make(map[interface{}][]interface{})
|
||||
for innerItem, ok := innernext(); ok; innerItem, ok = innernext() {
|
||||
innerKey := innerKeySelector(innerItem)
|
||||
innerLookup[innerKey] = append(innerLookup[innerKey], innerItem)
|
||||
}
|
||||
|
||||
var outerItem interface{}
|
||||
var innerGroup []interface{}
|
||||
innerLen, innerIndex := 0, 0
|
||||
|
||||
return func() (item interface{}, ok bool) {
|
||||
if innerIndex >= innerLen {
|
||||
has := false
|
||||
for !has {
|
||||
outerItem, ok = outernext()
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
innerGroup, has = innerLookup[outerKeySelector(outerItem)]
|
||||
innerLen = len(innerGroup)
|
||||
innerIndex = 0
|
||||
}
|
||||
}
|
||||
|
||||
item = resultSelector(outerItem, innerGroup[innerIndex])
|
||||
innerIndex++
|
||||
return item, true
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
+212
@@ -0,0 +1,212 @@
|
||||
package linq
|
||||
|
||||
import "sort"
|
||||
|
||||
type order struct {
|
||||
selector func(interface{}) interface{}
|
||||
compare comparer
|
||||
desc bool
|
||||
}
|
||||
|
||||
// OrderedQuery is the type returned from OrderBy, OrderByDescending
|
||||
// ThenBy and ThenByDescending functions.
|
||||
type OrderedQuery struct {
|
||||
Query
|
||||
original Query
|
||||
orders []order
|
||||
}
|
||||
|
||||
// OrderBy sorts the elements of a collection in ascending order.
|
||||
// Elements are sorted according to a key.
|
||||
func (q Query) OrderBy(
|
||||
selector func(interface{}) interface{}) OrderedQuery {
|
||||
return OrderedQuery{
|
||||
orders: []order{{selector: selector}},
|
||||
original: q,
|
||||
Query: Query{
|
||||
Iterate: func() Iterator {
|
||||
items := q.sort([]order{{selector: selector}})
|
||||
len := len(items)
|
||||
index := 0
|
||||
|
||||
return func() (item interface{}, ok bool) {
|
||||
ok = index < len
|
||||
if ok {
|
||||
item = items[index]
|
||||
index++
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// OrderByDescending sorts the elements of a collection in descending order.
|
||||
// Elements are sorted according to a key.
|
||||
func (q Query) OrderByDescending(
|
||||
selector func(interface{}) interface{}) OrderedQuery {
|
||||
return OrderedQuery{
|
||||
orders: []order{{selector: selector, desc: true}},
|
||||
original: q,
|
||||
Query: Query{
|
||||
Iterate: func() Iterator {
|
||||
items := q.sort([]order{{selector: selector, desc: true}})
|
||||
len := len(items)
|
||||
index := 0
|
||||
|
||||
return func() (item interface{}, ok bool) {
|
||||
ok = index < len
|
||||
if ok {
|
||||
item = items[index]
|
||||
index++
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// ThenBy performs a subsequent ordering of the elements in a collection
|
||||
// in ascending order. This method enables you to specify multiple sort criteria
|
||||
// by applying any number of ThenBy or ThenByDescending methods.
|
||||
func (oq OrderedQuery) ThenBy(
|
||||
selector func(interface{}) interface{}) OrderedQuery {
|
||||
return OrderedQuery{
|
||||
orders: append(oq.orders, order{selector: selector}),
|
||||
original: oq.original,
|
||||
Query: Query{
|
||||
Iterate: func() Iterator {
|
||||
items := oq.original.sort(append(oq.orders, order{selector: selector}))
|
||||
len := len(items)
|
||||
index := 0
|
||||
|
||||
return func() (item interface{}, ok bool) {
|
||||
ok = index < len
|
||||
if ok {
|
||||
item = items[index]
|
||||
index++
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// ThenByDescending performs a subsequent ordering of the elements in a collection
|
||||
// in descending order. This method enables you to specify multiple sort criteria
|
||||
// by applying any number of ThenBy or ThenByDescending methods.
|
||||
func (oq OrderedQuery) ThenByDescending(
|
||||
selector func(interface{}) interface{}) OrderedQuery {
|
||||
return OrderedQuery{
|
||||
orders: append(oq.orders, order{selector: selector, desc: true}),
|
||||
original: oq.original,
|
||||
Query: Query{
|
||||
Iterate: func() Iterator {
|
||||
items := oq.original.sort(append(oq.orders, order{selector: selector, desc: true}))
|
||||
len := len(items)
|
||||
index := 0
|
||||
|
||||
return func() (item interface{}, ok bool) {
|
||||
ok = index < len
|
||||
if ok {
|
||||
item = items[index]
|
||||
index++
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// Sort returns a new query by sorting elements with provided less function
|
||||
// in ascending order. The comparer function should return true if the parameter i
|
||||
// is less than j. While this method is uglier than chaining OrderBy, OrderByDescending,
|
||||
// ThenBy and ThenByDescending methods, it's performance is much better.
|
||||
func (q Query) Sort(less func(i, j interface{}) bool) Query {
|
||||
return Query{
|
||||
Iterate: func() Iterator {
|
||||
items := q.lessSort(less)
|
||||
len := len(items)
|
||||
index := 0
|
||||
|
||||
return func() (item interface{}, ok bool) {
|
||||
ok = index < len
|
||||
if ok {
|
||||
item = items[index]
|
||||
index++
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
type sorter struct {
|
||||
items []interface{}
|
||||
less func(i, j interface{}) bool
|
||||
}
|
||||
|
||||
func (s sorter) Len() int {
|
||||
return len(s.items)
|
||||
}
|
||||
|
||||
func (s sorter) Swap(i, j int) {
|
||||
s.items[i], s.items[j] = s.items[j], s.items[i]
|
||||
}
|
||||
|
||||
func (s sorter) Less(i, j int) bool {
|
||||
return s.less(s.items[i], s.items[j])
|
||||
}
|
||||
|
||||
func (q Query) sort(orders []order) (r []interface{}) {
|
||||
next := q.Iterate()
|
||||
for item, ok := next(); ok; item, ok = next() {
|
||||
r = append(r, item)
|
||||
}
|
||||
|
||||
for i, j := range orders {
|
||||
orders[i].compare = getComparer(j.selector(r[0]))
|
||||
}
|
||||
|
||||
s := sorter{
|
||||
items: r,
|
||||
less: func(i, j interface{}) bool {
|
||||
for _, order := range orders {
|
||||
x, y := order.selector(i), order.selector(j)
|
||||
switch order.compare(x, y) {
|
||||
case 0:
|
||||
continue
|
||||
case -1:
|
||||
return !order.desc
|
||||
default:
|
||||
return order.desc
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}}
|
||||
|
||||
sort.Sort(s)
|
||||
return
|
||||
}
|
||||
|
||||
func (q Query) lessSort(less func(i, j interface{}) bool) (r []interface{}) {
|
||||
next := q.Iterate()
|
||||
for item, ok := next(); ok; item, ok = next() {
|
||||
r = append(r, item)
|
||||
}
|
||||
|
||||
s := sorter{items: r, less: less}
|
||||
|
||||
sort.Sort(s)
|
||||
return
|
||||
}
|
||||
+394
@@ -0,0 +1,394 @@
|
||||
package linq
|
||||
|
||||
import (
|
||||
"math"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
// All determines whether all elements of a collection satisfy a condition.
|
||||
func (q Query) All(predicate func(interface{}) bool) bool {
|
||||
next := q.Iterate()
|
||||
|
||||
for item, ok := next(); ok; item, ok = next() {
|
||||
if !predicate(item) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
// Any determines whether any element of a collection exists.
|
||||
func (q Query) Any() bool {
|
||||
_, ok := q.Iterate()()
|
||||
return ok
|
||||
}
|
||||
|
||||
// AnyWith determines whether any element of a collection satisfies a condition.
|
||||
func (q Query) AnyWith(predicate func(interface{}) bool) bool {
|
||||
next := q.Iterate()
|
||||
|
||||
for item, ok := next(); ok; item, ok = next() {
|
||||
if predicate(item) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// Average computes the average of a collection of numeric values.
|
||||
func (q Query) Average() (r float64) {
|
||||
next := q.Iterate()
|
||||
item, ok := next()
|
||||
if !ok {
|
||||
return math.NaN()
|
||||
}
|
||||
|
||||
n := 1
|
||||
switch item.(type) {
|
||||
case int, int8, int16, int32, int64:
|
||||
conv := getIntConverter(item)
|
||||
sum := conv(item)
|
||||
|
||||
for item, ok = next(); ok; item, ok = next() {
|
||||
sum += conv(item)
|
||||
n++
|
||||
}
|
||||
|
||||
r = float64(sum)
|
||||
case uint, uint8, uint16, uint32, uint64:
|
||||
conv := getUIntConverter(item)
|
||||
sum := conv(item)
|
||||
|
||||
for item, ok = next(); ok; item, ok = next() {
|
||||
sum += conv(item)
|
||||
n++
|
||||
}
|
||||
|
||||
r = float64(sum)
|
||||
default:
|
||||
conv := getFloatConverter(item)
|
||||
r = conv(item)
|
||||
|
||||
for item, ok = next(); ok; item, ok = next() {
|
||||
r += conv(item)
|
||||
n++
|
||||
}
|
||||
}
|
||||
|
||||
return r / float64(n)
|
||||
}
|
||||
|
||||
// Contains determines whether a collection contains a specified element.
|
||||
func (q Query) Contains(value interface{}) bool {
|
||||
next := q.Iterate()
|
||||
|
||||
for item, ok := next(); ok; item, ok = next() {
|
||||
if item == value {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// Count returns the number of elements in a collection.
|
||||
func (q Query) Count() (r int) {
|
||||
next := q.Iterate()
|
||||
|
||||
for _, ok := next(); ok; _, ok = next() {
|
||||
r++
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// CountWith returns a number that represents how many elements
|
||||
// in the specified collection satisfy a condition.
|
||||
func (q Query) CountWith(predicate func(interface{}) bool) (r int) {
|
||||
next := q.Iterate()
|
||||
|
||||
for item, ok := next(); ok; item, ok = next() {
|
||||
if predicate(item) {
|
||||
r++
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// First returns the first element of a collection.
|
||||
func (q Query) First() interface{} {
|
||||
item, _ := q.Iterate()()
|
||||
return item
|
||||
}
|
||||
|
||||
// FirstWith returns the first element of a collection that satisfies
|
||||
// a specified condition.
|
||||
func (q Query) FirstWith(predicate func(interface{}) bool) interface{} {
|
||||
next := q.Iterate()
|
||||
|
||||
for item, ok := next(); ok; item, ok = next() {
|
||||
if predicate(item) {
|
||||
return item
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Last returns the last element of a collection.
|
||||
func (q Query) Last() (r interface{}) {
|
||||
next := q.Iterate()
|
||||
|
||||
for item, ok := next(); ok; item, ok = next() {
|
||||
r = item
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// LastWith returns the last element of a collection that satisfies
|
||||
// a specified condition.
|
||||
func (q Query) LastWith(predicate func(interface{}) bool) (r interface{}) {
|
||||
next := q.Iterate()
|
||||
|
||||
for item, ok := next(); ok; item, ok = next() {
|
||||
if predicate(item) {
|
||||
r = item
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// Max returns the maximum value in a collection of values.
|
||||
func (q Query) Max() (r interface{}) {
|
||||
next := q.Iterate()
|
||||
item, ok := next()
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
|
||||
compare := getComparer(item)
|
||||
r = item
|
||||
|
||||
for item, ok := next(); ok; item, ok = next() {
|
||||
if compare(item, r) > 0 {
|
||||
r = item
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// Min returns the minimum value in a collection of values.
|
||||
func (q Query) Min() (r interface{}) {
|
||||
next := q.Iterate()
|
||||
item, ok := next()
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
|
||||
compare := getComparer(item)
|
||||
r = item
|
||||
|
||||
for item, ok := next(); ok; item, ok = next() {
|
||||
if compare(item, r) < 0 {
|
||||
r = item
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// Results iterates over a collection and returnes slice of interfaces
|
||||
func (q Query) Results() (r []interface{}) {
|
||||
next := q.Iterate()
|
||||
|
||||
for item, ok := next(); ok; item, ok = next() {
|
||||
r = append(r, item)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// SequenceEqual determines whether two collections are equal.
|
||||
func (q Query) SequenceEqual(q2 Query) bool {
|
||||
next := q.Iterate()
|
||||
next2 := q2.Iterate()
|
||||
|
||||
for item, ok := next(); ok; item, ok = next() {
|
||||
item2, ok2 := next2()
|
||||
if !ok2 || item != item2 {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
_, ok2 := next2()
|
||||
return !ok2
|
||||
}
|
||||
|
||||
// Single returns the only element of a collection, and nil
|
||||
// if there is not exactly one element in the collection.
|
||||
func (q Query) Single() interface{} {
|
||||
next := q.Iterate()
|
||||
item, ok := next()
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
|
||||
_, ok = next()
|
||||
if ok {
|
||||
return nil
|
||||
}
|
||||
|
||||
return item
|
||||
}
|
||||
|
||||
// SingleWith returns the only element of a collection that satisfies
|
||||
// a specified condition, and nil if more than one such element exists.
|
||||
func (q Query) SingleWith(predicate func(interface{}) bool) (r interface{}) {
|
||||
next := q.Iterate()
|
||||
found := false
|
||||
|
||||
for item, ok := next(); ok; item, ok = next() {
|
||||
if predicate(item) {
|
||||
if found {
|
||||
return nil
|
||||
}
|
||||
|
||||
found = true
|
||||
r = item
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// SumInts computes the sum of a collection of numeric values.
|
||||
//
|
||||
// Values can be of any integer type: int, int8, int16, int32, int64.
|
||||
// The result is int64. Method returns zero if collection contains no elements.
|
||||
func (q Query) SumInts() (r int64) {
|
||||
next := q.Iterate()
|
||||
item, ok := next()
|
||||
if !ok {
|
||||
return 0
|
||||
}
|
||||
|
||||
conv := getIntConverter(item)
|
||||
r = conv(item)
|
||||
|
||||
for item, ok = next(); ok; item, ok = next() {
|
||||
r += conv(item)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// SumUInts computes the sum of a collection of numeric values.
|
||||
//
|
||||
// Values can be of any unsigned integer type: uint, uint8, uint16, uint32, uint64.
|
||||
// The result is uint64. Method returns zero if collection contains no elements.
|
||||
func (q Query) SumUInts() (r uint64) {
|
||||
next := q.Iterate()
|
||||
item, ok := next()
|
||||
if !ok {
|
||||
return 0
|
||||
}
|
||||
|
||||
conv := getUIntConverter(item)
|
||||
r = conv(item)
|
||||
|
||||
for item, ok = next(); ok; item, ok = next() {
|
||||
r += conv(item)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// SumFloats computes the sum of a collection of numeric values.
|
||||
//
|
||||
// Values can be of any float type: float32 or float64. The result is float64.
|
||||
// Method returns zero if collection contains no elements.
|
||||
func (q Query) SumFloats() (r float64) {
|
||||
next := q.Iterate()
|
||||
item, ok := next()
|
||||
if !ok {
|
||||
return 0
|
||||
}
|
||||
|
||||
conv := getFloatConverter(item)
|
||||
r = conv(item)
|
||||
|
||||
for item, ok = next(); ok; item, ok = next() {
|
||||
r += conv(item)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// ToChannel iterates over a collection and outputs each element
|
||||
// to a channel, then closes it.
|
||||
func (q Query) ToChannel(result chan<- interface{}) {
|
||||
next := q.Iterate()
|
||||
|
||||
for item, ok := next(); ok; item, ok = next() {
|
||||
result <- item
|
||||
}
|
||||
|
||||
close(result)
|
||||
}
|
||||
|
||||
// ToMap iterates over a collection and populates result map with elements.
|
||||
// Collection elements have to be of KeyValue type to use this method.
|
||||
// To populate a map with elements of different type use ToMapBy method.
|
||||
func (q Query) ToMap(result interface{}) {
|
||||
q.ToMapBy(
|
||||
result,
|
||||
func(i interface{}) interface{} {
|
||||
return i.(KeyValue).Key
|
||||
},
|
||||
func(i interface{}) interface{} {
|
||||
return i.(KeyValue).Value
|
||||
})
|
||||
}
|
||||
|
||||
// ToMapBy iterates over a collection and populates result map with elements.
|
||||
// Functions keySelector and valueSelector are executed for each element of the collection
|
||||
// to generate key and value for the map. Generated key and value types must be assignable
|
||||
// to the map's key and value types.
|
||||
func (q Query) ToMapBy(
|
||||
result interface{},
|
||||
keySelector func(interface{}) interface{},
|
||||
valueSelector func(interface{}) interface{},
|
||||
) {
|
||||
res := reflect.ValueOf(result)
|
||||
m := reflect.Indirect(res)
|
||||
next := q.Iterate()
|
||||
|
||||
for item, ok := next(); ok; item, ok = next() {
|
||||
key := reflect.ValueOf(keySelector(item))
|
||||
value := reflect.ValueOf(valueSelector(item))
|
||||
|
||||
m.SetMapIndex(key, value)
|
||||
}
|
||||
|
||||
res.Elem().Set(m)
|
||||
}
|
||||
|
||||
// ToSlice iterates over a collection and populates result slice with elements.
|
||||
// Collection elements must be assignable to the slice's element type.
|
||||
func (q Query) ToSlice(result interface{}) {
|
||||
res := reflect.ValueOf(result)
|
||||
slice := reflect.Indirect(res)
|
||||
next := q.Iterate()
|
||||
|
||||
for item, ok := next(); ok; item, ok = next() {
|
||||
slice = reflect.Append(slice, reflect.ValueOf(item))
|
||||
}
|
||||
|
||||
res.Elem().Set(slice)
|
||||
}
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
package linq
|
||||
|
||||
// Reverse inverts the order of the elements in a collection.
|
||||
//
|
||||
// Unlike OrderBy, this sorting method does not consider the actual values themselves
|
||||
// in determining the order. Rather, it just returns the elements in the reverse order
|
||||
// from which they are produced by the underlying source.
|
||||
func (q Query) Reverse() Query {
|
||||
return Query{
|
||||
Iterate: func() Iterator {
|
||||
next := q.Iterate()
|
||||
|
||||
items := []interface{}{}
|
||||
for item, ok := next(); ok; item, ok = next() {
|
||||
items = append(items, item)
|
||||
}
|
||||
|
||||
index := len(items) - 1
|
||||
return func() (item interface{}, ok bool) {
|
||||
if index < 0 {
|
||||
return
|
||||
}
|
||||
|
||||
item, ok = items[index], true
|
||||
index--
|
||||
return
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
+71
@@ -0,0 +1,71 @@
|
||||
package linq
|
||||
|
||||
// Select projects each element of a collection into a new form.
|
||||
// Returns a query with the result of invoking the transform function
|
||||
// on each element of original source.
|
||||
//
|
||||
// This projection method requires the transform function, selector,
|
||||
// to produce one value for each value in the source collection.
|
||||
// If selector returns a value that is itself a collection,
|
||||
// it is up to the consumer to traverse the subcollections manually.
|
||||
// In such a situation, it might be better for your query to return a single
|
||||
// coalesced collection of values. To achieve this, use the SelectMany method
|
||||
// instead of Select. Although SelectMany works similarly to Select,
|
||||
// it differs in that the transform function returns a collection
|
||||
// that is then expanded by SelectMany before it is returned.
|
||||
func (q Query) Select(selector func(interface{}) interface{}) Query {
|
||||
return Query{
|
||||
Iterate: func() Iterator {
|
||||
next := q.Iterate()
|
||||
|
||||
return func() (item interface{}, ok bool) {
|
||||
var it interface{}
|
||||
it, ok = next()
|
||||
if ok {
|
||||
item = selector(it)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// SelectIndexed projects each element of a collection into a new form
|
||||
// by incorporating the element's index. Returns a query with the result
|
||||
// of invoking the transform function on each element of original source.
|
||||
//
|
||||
// The first argument to selector represents the zero-based index of that element
|
||||
// in the source collection. This can be useful if the elements are in a known order
|
||||
// and you want to do something with an element at a particular index,
|
||||
// for example. It can also be useful if you want to retrieve the index of one
|
||||
// or more elements. The second argument to selector represents the element to process.
|
||||
//
|
||||
// This projection method requires the transform function, selector,
|
||||
// to produce one value for each value in the source collection.
|
||||
// If selector returns a value that is itself a collection,
|
||||
// it is up to the consumer to traverse the subcollections manually.
|
||||
// In such a situation, it might be better for your query to return a single
|
||||
// coalesced collection of values. To achieve this, use the SelectMany method
|
||||
// instead of Select. Although SelectMany works similarly to Select,
|
||||
// it differs in that the transform function returns a collection
|
||||
// that is then expanded by SelectMany before it is returned.
|
||||
func (q Query) SelectIndexed(selector func(int, interface{}) interface{}) Query {
|
||||
return Query{
|
||||
Iterate: func() Iterator {
|
||||
next := q.Iterate()
|
||||
index := 0
|
||||
|
||||
return func() (item interface{}, ok bool) {
|
||||
var it interface{}
|
||||
it, ok = next()
|
||||
if ok {
|
||||
item = selector(index, it)
|
||||
index++
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
+151
@@ -0,0 +1,151 @@
|
||||
package linq
|
||||
|
||||
// SelectMany projects each element of a collection to a Query, iterates and
|
||||
// flattens the resulting collection into one collection.
|
||||
func (q Query) SelectMany(selector func(interface{}) Query) Query {
|
||||
return Query{
|
||||
Iterate: func() Iterator {
|
||||
outernext := q.Iterate()
|
||||
var inner interface{}
|
||||
var innernext Iterator
|
||||
|
||||
return func() (item interface{}, ok bool) {
|
||||
for !ok {
|
||||
if inner == nil {
|
||||
inner, ok = outernext()
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
innernext = selector(inner).Iterate()
|
||||
}
|
||||
|
||||
item, ok = innernext()
|
||||
if !ok {
|
||||
inner = nil
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// SelectManyIndexed projects each element of a collection to a Query, iterates and
|
||||
// flattens the resulting collection into one collection.
|
||||
//
|
||||
// The first argument to selector represents the zero-based index of that element
|
||||
// in the source collection. This can be useful if the elements are in a known order
|
||||
// and you want to do something with an element at a particular index, for example.
|
||||
// It can also be useful if you want to retrieve the index of one or more elements.
|
||||
// The second argument to selector represents the element to process.
|
||||
func (q Query) SelectManyIndexed(selector func(int, interface{}) Query) Query {
|
||||
return Query{
|
||||
Iterate: func() Iterator {
|
||||
outernext := q.Iterate()
|
||||
index := 0
|
||||
var inner interface{}
|
||||
var innernext Iterator
|
||||
|
||||
return func() (item interface{}, ok bool) {
|
||||
for !ok {
|
||||
if inner == nil {
|
||||
inner, ok = outernext()
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
innernext = selector(index, inner).Iterate()
|
||||
index++
|
||||
}
|
||||
|
||||
item, ok = innernext()
|
||||
if !ok {
|
||||
inner = nil
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// SelectManyBy projects each element of a collection to a Query, iterates and
|
||||
// flattens the resulting collection into one collection, and invokes
|
||||
// a result selector function on each element therein.
|
||||
func (q Query) SelectManyBy(
|
||||
selector func(interface{}) Query,
|
||||
resultSelector func(interface{}, interface{}) interface{},
|
||||
) Query {
|
||||
|
||||
return Query{
|
||||
Iterate: func() Iterator {
|
||||
outernext := q.Iterate()
|
||||
var outer interface{}
|
||||
var innernext Iterator
|
||||
|
||||
return func() (item interface{}, ok bool) {
|
||||
for !ok {
|
||||
if outer == nil {
|
||||
outer, ok = outernext()
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
innernext = selector(outer).Iterate()
|
||||
}
|
||||
|
||||
item, ok = innernext()
|
||||
if !ok {
|
||||
outer = nil
|
||||
}
|
||||
}
|
||||
|
||||
item = resultSelector(outer, item)
|
||||
return
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// SelectManyByIndexed projects each element of a collection to a Query, iterates and
|
||||
// flattens the resulting collection into one collection, and invokes
|
||||
// a result selector function on each element therein.
|
||||
// The index of each source element is used in the intermediate projected form
|
||||
// of that element.
|
||||
func (q Query) SelectManyByIndexed(selector func(int, interface{}) Query,
|
||||
resultSelector func(interface{}, interface{}) interface{}) Query {
|
||||
|
||||
return Query{
|
||||
Iterate: func() Iterator {
|
||||
outernext := q.Iterate()
|
||||
index := 0
|
||||
var outer interface{}
|
||||
var innernext Iterator
|
||||
|
||||
return func() (item interface{}, ok bool) {
|
||||
for !ok {
|
||||
if outer == nil {
|
||||
outer, ok = outernext()
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
innernext = selector(index, outer).Iterate()
|
||||
index++
|
||||
}
|
||||
|
||||
item, ok = innernext()
|
||||
if !ok {
|
||||
outer = nil
|
||||
}
|
||||
}
|
||||
|
||||
item = resultSelector(outer, item)
|
||||
return
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
+91
@@ -0,0 +1,91 @@
|
||||
package linq
|
||||
|
||||
// Skip bypasses a specified number of elements in a collection
|
||||
// and then returns the remaining elements.
|
||||
func (q Query) Skip(count int) Query {
|
||||
return Query{
|
||||
Iterate: func() Iterator {
|
||||
next := q.Iterate()
|
||||
n := count
|
||||
|
||||
return func() (item interface{}, ok bool) {
|
||||
for ; n > 0; n-- {
|
||||
item, ok = next()
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
return next()
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// SkipWhile bypasses elements in a collection as long as a specified condition is true
|
||||
// and then returns the remaining elements.
|
||||
//
|
||||
// This method tests each element by using predicate and skips the element
|
||||
// if the result is true. After the predicate function returns false for an element,
|
||||
// that element and the remaining elements in source are returned
|
||||
// and there are no more invocations of predicate.
|
||||
func (q Query) SkipWhile(predicate func(interface{}) bool) Query {
|
||||
return Query{
|
||||
Iterate: func() Iterator {
|
||||
next := q.Iterate()
|
||||
ready := false
|
||||
|
||||
return func() (item interface{}, ok bool) {
|
||||
for !ready {
|
||||
item, ok = next()
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
ready = !predicate(item)
|
||||
if ready {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
return next()
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// SkipWhileIndexed bypasses elements in a collection as long as a specified condition
|
||||
// is true and then returns the remaining elements. The element's index is used
|
||||
// in the logic of the predicate function.
|
||||
//
|
||||
// This method tests each element by using predicate and skips the element
|
||||
// if the result is true. After the predicate function returns false for an element,
|
||||
// that element and the remaining elements in source are returned
|
||||
// and there are no more invocations of predicate.
|
||||
func (q Query) SkipWhileIndexed(predicate func(int, interface{}) bool) Query {
|
||||
return Query{
|
||||
Iterate: func() Iterator {
|
||||
next := q.Iterate()
|
||||
ready := false
|
||||
index := 0
|
||||
|
||||
return func() (item interface{}, ok bool) {
|
||||
for !ready {
|
||||
item, ok = next()
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
ready = !predicate(index, item)
|
||||
if ready {
|
||||
return
|
||||
}
|
||||
|
||||
index++
|
||||
}
|
||||
|
||||
return next()
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
+84
@@ -0,0 +1,84 @@
|
||||
package linq
|
||||
|
||||
// Take returns a specified number of contiguous elements from the start of a collection.
|
||||
func (q Query) Take(count int) Query {
|
||||
return Query{
|
||||
Iterate: func() Iterator {
|
||||
next := q.Iterate()
|
||||
n := count
|
||||
|
||||
return func() (item interface{}, ok bool) {
|
||||
if n <= 0 {
|
||||
return
|
||||
}
|
||||
|
||||
n--
|
||||
return next()
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// TakeWhile returns elements from a collection as long as a specified condition is true,
|
||||
// and then skips the remaining elements.
|
||||
func (q Query) TakeWhile(predicate func(interface{}) bool) Query {
|
||||
return Query{
|
||||
Iterate: func() Iterator {
|
||||
next := q.Iterate()
|
||||
done := false
|
||||
|
||||
return func() (item interface{}, ok bool) {
|
||||
if done {
|
||||
return
|
||||
}
|
||||
|
||||
item, ok = next()
|
||||
if !ok {
|
||||
done = true
|
||||
return
|
||||
}
|
||||
|
||||
if predicate(item) {
|
||||
return
|
||||
}
|
||||
|
||||
done = true
|
||||
return nil, false
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// TakeWhileIndexed returns elements from a collection as long as a specified condition
|
||||
// is true. The element's index is used in the logic of the predicate function.
|
||||
// The first argument of predicate represents the zero-based index of the element
|
||||
// within collection. The second argument represents the element to test.
|
||||
func (q Query) TakeWhileIndexed(predicate func(int, interface{}) bool) Query {
|
||||
return Query{
|
||||
Iterate: func() Iterator {
|
||||
next := q.Iterate()
|
||||
done := false
|
||||
index := 0
|
||||
|
||||
return func() (item interface{}, ok bool) {
|
||||
if done {
|
||||
return
|
||||
}
|
||||
|
||||
item, ok = next()
|
||||
if !ok {
|
||||
done = true
|
||||
return
|
||||
}
|
||||
|
||||
if predicate(index, item) {
|
||||
index++
|
||||
return
|
||||
}
|
||||
|
||||
done = true
|
||||
return nil, false
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
+41
@@ -0,0 +1,41 @@
|
||||
package linq
|
||||
|
||||
// Union produces the set union of two collections.
|
||||
//
|
||||
// This method excludes duplicates from the return set.
|
||||
// This is different behavior to the Concat method,
|
||||
// which returns all the elements in the input collection
|
||||
// including duplicates.
|
||||
func (q Query) Union(q2 Query) Query {
|
||||
return Query{
|
||||
Iterate: func() Iterator {
|
||||
next := q.Iterate()
|
||||
next2 := q2.Iterate()
|
||||
|
||||
set := make(map[interface{}]bool)
|
||||
use1 := true
|
||||
|
||||
return func() (item interface{}, ok bool) {
|
||||
if use1 {
|
||||
for item, ok = next(); ok; item, ok = next() {
|
||||
if _, has := set[item]; !has {
|
||||
set[item] = true
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
use1 = false
|
||||
}
|
||||
|
||||
for item, ok = next2(); ok; item, ok = next2() {
|
||||
if _, has := set[item]; !has {
|
||||
set[item] = true
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
+46
@@ -0,0 +1,46 @@
|
||||
package linq
|
||||
|
||||
// Where filters a collection of values based on a predicate.
|
||||
func (q Query) Where(predicate func(interface{}) bool) Query {
|
||||
return Query{
|
||||
Iterate: func() Iterator {
|
||||
next := q.Iterate()
|
||||
|
||||
return func() (item interface{}, ok bool) {
|
||||
for item, ok = next(); ok; item, ok = next() {
|
||||
if predicate(item) {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// WhereIndexed filters a collection of values based on a predicate.
|
||||
// Each element's index is used in the logic of the predicate function.
|
||||
//
|
||||
// The first argument represents the zero-based index of the element within collection.
|
||||
// The second argument of predicate represents the element to test.
|
||||
func (q Query) WhereIndexed(predicate func(int, interface{}) bool) Query {
|
||||
return Query{
|
||||
Iterate: func() Iterator {
|
||||
next := q.Iterate()
|
||||
index := 0
|
||||
|
||||
return func() (item interface{}, ok bool) {
|
||||
for item, ok = next(); ok; item, ok = next() {
|
||||
if predicate(index, item) {
|
||||
return
|
||||
}
|
||||
|
||||
index++
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
+35
@@ -0,0 +1,35 @@
|
||||
package linq
|
||||
|
||||
// Zip applies a specified function to the corresponding elements
|
||||
// of two collections, producing a collection of the results.
|
||||
//
|
||||
// The method steps through the two input collections, applying function
|
||||
// resultSelector to corresponding elements of the two collections.
|
||||
// The method returns a collection of the values that are returned by resultSelector.
|
||||
// If the input collections do not have the same number of elements,
|
||||
// the method combines elements until it reaches the end of one of the collections.
|
||||
// For example, if one collection has three elements and the other one has four,
|
||||
// the result collection has only three elements.
|
||||
func (q Query) Zip(
|
||||
q2 Query,
|
||||
resultSelector func(interface{}, interface{}) interface{},
|
||||
) Query {
|
||||
|
||||
return Query{
|
||||
Iterate: func() Iterator {
|
||||
next1 := q.Iterate()
|
||||
next2 := q2.Iterate()
|
||||
|
||||
return func() (item interface{}, ok bool) {
|
||||
item1, ok1 := next1()
|
||||
item2, ok2 := next2()
|
||||
|
||||
if ok1 && ok2 {
|
||||
return resultSelector(item1, item2), true
|
||||
}
|
||||
|
||||
return nil, false
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
Vendored
+2
@@ -1,2 +1,4 @@
|
||||
# github.com/ahmetalpbalkan/go-linq v2.0.0-rc0+incompatible
|
||||
github.com/ahmetalpbalkan/go-linq
|
||||
# github.com/go-ini/ini v1.57.0
|
||||
github.com/go-ini/ini
|
||||
|
||||
Reference in New Issue
Block a user