groupby.go 2.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081
  1. package help
  2. // Group is a type that is used to store the result of GroupBy method.
  3. type Group struct {
  4. Key interface{}
  5. Group []interface{}
  6. }
  7. // GroupBy method groups the elements of a collection according to a specified
  8. // key selector function and projects the elements for each group by using a
  9. // specified function.
  10. func (q Query) GroupBy(keySelector func(interface{}) interface{},
  11. elementSelector func(interface{}) interface{}) Query {
  12. return Query{
  13. func() Iterator {
  14. next := q.Iterate()
  15. set := make(map[interface{}][]interface{})
  16. for item, ok := next(); ok; item, ok = next() {
  17. key := keySelector(item)
  18. set[key] = append(set[key], elementSelector(item))
  19. }
  20. len := len(set)
  21. idx := 0
  22. groups := make([]Group, len)
  23. for k, v := range set {
  24. groups[idx] = Group{k, v}
  25. idx++
  26. }
  27. index := 0
  28. return func() (item interface{}, ok bool) {
  29. ok = index < len
  30. if ok {
  31. item = groups[index]
  32. index++
  33. }
  34. return
  35. }
  36. },
  37. }
  38. }
  39. // GroupByT is the typed version of GroupBy.
  40. //
  41. // - keySelectorFn is of type "func(TSource) TKey"
  42. // - elementSelectorFn is of type "func(TSource) TElement"
  43. //
  44. // NOTE: GroupBy has better performance than GroupByT.
  45. func (q Query) GroupByT(keySelectorFn interface{},
  46. elementSelectorFn interface{}) Query {
  47. keySelectorGenericFunc, err := newGenericFunc(
  48. "GroupByT", "keySelectorFn", keySelectorFn,
  49. simpleParamValidator(newElemTypeSlice(new(genericType)), newElemTypeSlice(new(genericType))),
  50. )
  51. if err != nil {
  52. panic(err)
  53. }
  54. keySelectorFunc := func(item interface{}) interface{} {
  55. return keySelectorGenericFunc.Call(item)
  56. }
  57. elementSelectorGenericFunc, err := newGenericFunc(
  58. "GroupByT", "elementSelectorFn", elementSelectorFn,
  59. simpleParamValidator(newElemTypeSlice(new(genericType)), newElemTypeSlice(new(genericType))),
  60. )
  61. if err != nil {
  62. panic(err)
  63. }
  64. elementSelectorFunc := func(item interface{}) interface{} {
  65. return elementSelectorGenericFunc.Call(item)
  66. }
  67. return q.GroupBy(keySelectorFunc, elementSelectorFunc)
  68. }