123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105 |
- package help
- // 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
- }
- },
- }
- }
- // JoinT is the typed version of Join.
- //
- // - outerKeySelectorFn is of type "func(TOuter) TKey"
- // - innerKeySelectorFn is of type "func(TInner) TKey"
- // - resultSelectorFn is of type "func(TOuter,TInner) TResult"
- //
- // NOTE: Join has better performance than JoinT.
- func (q Query) JoinT(inner Query,
- outerKeySelectorFn interface{},
- innerKeySelectorFn interface{},
- resultSelectorFn interface{}) Query {
- outerKeySelectorGenericFunc, err := newGenericFunc(
- "JoinT", "outerKeySelectorFn", outerKeySelectorFn,
- simpleParamValidator(newElemTypeSlice(new(genericType)), newElemTypeSlice(new(genericType))),
- )
- if err != nil {
- panic(err)
- }
- outerKeySelectorFunc := func(item interface{}) interface{} {
- return outerKeySelectorGenericFunc.Call(item)
- }
- innerKeySelectorFuncGenericFunc, err := newGenericFunc(
- "JoinT", "innerKeySelectorFn",
- innerKeySelectorFn,
- simpleParamValidator(newElemTypeSlice(new(genericType)), newElemTypeSlice(new(genericType))),
- )
- if err != nil {
- panic(err)
- }
- innerKeySelectorFunc := func(item interface{}) interface{} {
- return innerKeySelectorFuncGenericFunc.Call(item)
- }
- resultSelectorGenericFunc, err := newGenericFunc(
- "JoinT", "resultSelectorFn", resultSelectorFn,
- simpleParamValidator(newElemTypeSlice(new(genericType), new(genericType)), newElemTypeSlice(new(genericType))),
- )
- if err != nil {
- panic(err)
- }
- resultSelectorFunc := func(outer interface{}, inner interface{}) interface{} {
- return resultSelectorGenericFunc.Call(outer, inner)
- }
- return q.Join(inner, outerKeySelectorFunc, innerKeySelectorFunc, resultSelectorFunc)
- }
|