123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674 |
- package help
- 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
- }
- // AllT is the typed version of All.
- //
- // - predicateFn is of type "func(TSource) bool"
- //
- // NOTE: All has better performance than AllT.
- func (q Query) AllT(predicateFn interface{}) bool {
- predicateGenericFunc, err := newGenericFunc(
- "AllT", "predicateFn", predicateFn,
- simpleParamValidator(newElemTypeSlice(new(genericType)), newElemTypeSlice(new(bool))),
- )
- if err != nil {
- panic(err)
- }
- predicateFunc := func(item interface{}) bool {
- return predicateGenericFunc.Call(item).(bool)
- }
- return q.All(predicateFunc)
- }
- // 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
- }
- // AnyWithT is the typed version of AnyWith.
- //
- // - predicateFn is of type "func(TSource) bool"
- //
- // NOTE: AnyWith has better performance than AnyWithT.
- func (q Query) AnyWithT(predicateFn interface{}) bool {
- predicateGenericFunc, err := newGenericFunc(
- "AnyWithT", "predicateFn", predicateFn,
- simpleParamValidator(newElemTypeSlice(new(genericType)), newElemTypeSlice(new(bool))),
- )
- if err != nil {
- panic(err)
- }
- predicateFunc := func(item interface{}) bool {
- return predicateGenericFunc.Call(item).(bool)
- }
- return q.AnyWith(predicateFunc)
- }
- // 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
- }
- // CountWithT is the typed version of CountWith.
- //
- // - predicateFn is of type "func(TSource) bool"
- //
- // NOTE: CountWith has better performance than CountWithT.
- func (q Query) CountWithT(predicateFn interface{}) int {
- predicateGenericFunc, err := newGenericFunc(
- "CountWithT", "predicateFn", predicateFn,
- simpleParamValidator(newElemTypeSlice(new(genericType)), newElemTypeSlice(new(bool))),
- )
- if err != nil {
- panic(err)
- }
- predicateFunc := func(item interface{}) bool {
- return predicateGenericFunc.Call(item).(bool)
- }
- return q.CountWith(predicateFunc)
- }
- // 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
- }
- // FirstWithT is the typed version of FirstWith.
- //
- // - predicateFn is of type "func(TSource) bool"
- //
- // NOTE: FirstWith has better performance than FirstWithT.
- func (q Query) FirstWithT(predicateFn interface{}) interface{} {
- predicateGenericFunc, err := newGenericFunc(
- "FirstWithT", "predicateFn", predicateFn,
- simpleParamValidator(newElemTypeSlice(new(genericType)), newElemTypeSlice(new(bool))),
- )
- if err != nil {
- panic(err)
- }
- predicateFunc := func(item interface{}) bool {
- return predicateGenericFunc.Call(item).(bool)
- }
- return q.FirstWith(predicateFunc)
- }
- // ForEach performs the specified action on each element of a collection.
- func (q Query) ForEach(action func(interface{})) {
- next := q.Iterate()
- for item, ok := next(); ok; item, ok = next() {
- action(item)
- }
- }
- // ForEachT is the typed version of ForEach.
- //
- // - actionFn is of type "func(TSource)"
- //
- // NOTE: ForEach has better performance than ForEachT.
- func (q Query) ForEachT(actionFn interface{}) {
- actionGenericFunc, err := newGenericFunc(
- "ForEachT", "actionFn", actionFn,
- simpleParamValidator(newElemTypeSlice(new(genericType)), nil),
- )
- if err != nil {
- panic(err)
- }
- actionFunc := func(item interface{}) {
- actionGenericFunc.Call(item)
- }
- q.ForEach(actionFunc)
- }
- // ForEachIndexed performs the specified action on each element of a collection.
- //
- // The first argument to action 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 action represents the
- // element to process.
- func (q Query) ForEachIndexed(action func(int, interface{})) {
- next := q.Iterate()
- index := 0
- for item, ok := next(); ok; item, ok = next() {
- action(index, item)
- index++
- }
- }
- // ForEachIndexedT is the typed version of ForEachIndexed.
- //
- // - actionFn is of type "func(int, TSource)"
- //
- // NOTE: ForEachIndexed has better performance than ForEachIndexedT.
- func (q Query) ForEachIndexedT(actionFn interface{}) {
- actionGenericFunc, err := newGenericFunc(
- "ForEachIndexedT", "actionFn", actionFn,
- simpleParamValidator(newElemTypeSlice(new(int), new(genericType)), nil),
- )
- if err != nil {
- panic(err)
- }
- actionFunc := func(index int, item interface{}) {
- actionGenericFunc.Call(index, item)
- }
- q.ForEachIndexed(actionFunc)
- }
- // 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
- }
- // LastWithT is the typed version of LastWith.
- //
- // - predicateFn is of type "func(TSource) bool"
- //
- // NOTE: LastWith has better performance than LastWithT.
- func (q Query) LastWithT(predicateFn interface{}) interface{} {
- predicateGenericFunc, err := newGenericFunc(
- "LastWithT", "predicateFn", predicateFn,
- simpleParamValidator(newElemTypeSlice(new(genericType)), newElemTypeSlice(new(bool))),
- )
- if err != nil {
- panic(err)
- }
- predicateFunc := func(item interface{}) bool {
- return predicateGenericFunc.Call(item).(bool)
- }
- return q.LastWith(predicateFunc)
- }
- // 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
- }
- // SingleWithT is the typed version of SingleWith.
- //
- // - predicateFn is of type "func(TSource) bool"
- //
- // NOTE: SingleWith has better performance than SingleWithT.
- func (q Query) SingleWithT(predicateFn interface{}) interface{} {
- predicateGenericFunc, err := newGenericFunc(
- "SingleWithT", "predicateFn", predicateFn,
- simpleParamValidator(newElemTypeSlice(new(genericType)), newElemTypeSlice(new(bool))),
- )
- if err != nil {
- panic(err)
- }
- predicateFunc := func(item interface{}) bool {
- return predicateGenericFunc.Call(item).(bool)
- }
- return q.SingleWith(predicateFunc)
- }
- // 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)
- }
- // ToChannelT is the typed version of ToChannel.
- //
- // - result is of type "chan TSource"
- //
- // NOTE: ToChannel has better performance than ToChannelT.
- func (q Query) ToChannelT(result interface{}) {
- r := reflect.ValueOf(result)
- next := q.Iterate()
- for item, ok := next(); ok; item, ok = next() {
- r.Send(reflect.ValueOf(item))
- }
- r.Close()
- }
- // 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. ToMap
- // doesn't empty the result map before populating it.
- 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 the 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.
- // ToMapBy doesn't empty the result map before populating it.
- 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)
- }
- // ToMapByT is the typed version of ToMapBy.
- //
- // - keySelectorFn is of type "func(TSource)TKey"
- // - valueSelectorFn is of type "func(TSource)TValue"
- //
- // NOTE: ToMapBy has better performance than ToMapByT.
- func (q Query) ToMapByT(result interface{},
- keySelectorFn interface{}, valueSelectorFn interface{}) {
- keySelectorGenericFunc, err := newGenericFunc(
- "ToMapByT", "keySelectorFn", keySelectorFn,
- simpleParamValidator(newElemTypeSlice(new(genericType)), newElemTypeSlice(new(genericType))),
- )
- if err != nil {
- panic(err)
- }
- keySelectorFunc := func(item interface{}) interface{} {
- return keySelectorGenericFunc.Call(item)
- }
- valueSelectorGenericFunc, err := newGenericFunc(
- "ToMapByT", "valueSelectorFn", valueSelectorFn,
- simpleParamValidator(newElemTypeSlice(new(genericType)), newElemTypeSlice(new(genericType))),
- )
- if err != nil {
- panic(err)
- }
- valueSelectorFunc := func(item interface{}) interface{} {
- return valueSelectorGenericFunc.Call(item)
- }
- q.ToMapBy(result, keySelectorFunc, valueSelectorFunc)
- }
- // ToSlice iterates over a collection and saves the results in the slice pointed
- // by v. It overwrites the existing slice, starting from index 0.
- //
- // If the slice pointed by v has sufficient capacity, v will be pointed to a
- // resliced slice. If it does not, a new underlying array will be allocated and
- // v will point to it.
- func (q Query) ToSlice(v interface{}) {
- res := reflect.ValueOf(v)
- slice := reflect.Indirect(res)
- cap := slice.Cap()
- res.Elem().Set(slice.Slice(0, cap)) // make len(slice)==cap(slice) from now on
- next := q.Iterate()
- index := 0
- for item, ok := next(); ok; item, ok = next() {
- if index >= cap {
- slice, cap = grow(slice)
- }
- slice.Index(index).Set(reflect.ValueOf(item))
- index++
- }
- // reslice the len(res)==cap(res) actual res size
- res.Elem().Set(slice.Slice(0, index))
- }
- // grow grows the slice s by doubling its capacity, then it returns the new
- // slice (resliced to its full capacity) and the new capacity.
- func grow(s reflect.Value) (v reflect.Value, newCap int) {
- cap := s.Cap()
- if cap == 0 {
- cap = 1
- } else {
- cap *= 2
- }
- newSlice := reflect.MakeSlice(s.Type(), cap, cap)
- reflect.Copy(newSlice, s)
- return newSlice, cap
- }
|