123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313 |
- package help
- 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
- }
- },
- },
- }
- }
- // OrderByT is the typed version of OrderBy.
- //
- // - selectorFn is of type "func(TSource) TKey"
- //
- // NOTE: OrderBy has better performance than OrderByT.
- func (q Query) OrderByT(selectorFn interface{}) OrderedQuery {
- selectorGenericFunc, err := newGenericFunc(
- "OrderByT", "selectorFn", selectorFn,
- simpleParamValidator(newElemTypeSlice(new(genericType)), newElemTypeSlice(new(genericType))),
- )
- if err != nil {
- panic(err)
- }
- selectorFunc := func(item interface{}) interface{} {
- return selectorGenericFunc.Call(item)
- }
- return q.OrderBy(selectorFunc)
- }
- // 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
- }
- },
- },
- }
- }
- // OrderByDescendingT is the typed version of OrderByDescending.
- // - selectorFn is of type "func(TSource) TKey"
- // NOTE: OrderByDescending has better performance than OrderByDescendingT.
- func (q Query) OrderByDescendingT(selectorFn interface{}) OrderedQuery {
- selectorGenericFunc, err := newGenericFunc(
- "OrderByDescendingT", "selectorFn", selectorFn,
- simpleParamValidator(newElemTypeSlice(new(genericType)), newElemTypeSlice(new(genericType))),
- )
- if err != nil {
- panic(err)
- }
- selectorFunc := func(item interface{}) interface{} {
- return selectorGenericFunc.Call(item)
- }
- return q.OrderByDescending(selectorFunc)
- }
- // 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
- }
- },
- },
- }
- }
- // ThenByT is the typed version of ThenBy.
- // - selectorFn is of type "func(TSource) TKey"
- // NOTE: ThenBy has better performance than ThenByT.
- func (oq OrderedQuery) ThenByT(selectorFn interface{}) OrderedQuery {
- selectorGenericFunc, err := newGenericFunc(
- "ThenByT", "selectorFn", selectorFn,
- simpleParamValidator(newElemTypeSlice(new(genericType)), newElemTypeSlice(new(genericType))),
- )
- if err != nil {
- panic(err)
- }
- selectorFunc := func(item interface{}) interface{} {
- return selectorGenericFunc.Call(item)
- }
- return oq.ThenBy(selectorFunc)
- }
- // 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
- }
- },
- },
- }
- }
- // ThenByDescendingT is the typed version of ThenByDescending.
- // - selectorFn is of type "func(TSource) TKey"
- // NOTE: ThenByDescending has better performance than ThenByDescendingT.
- func (oq OrderedQuery) ThenByDescendingT(selectorFn interface{}) OrderedQuery {
- selectorFunc, ok := selectorFn.(func(interface{}) interface{})
- if !ok {
- selectorGenericFunc, err := newGenericFunc(
- "ThenByDescending", "selectorFn", selectorFn,
- simpleParamValidator(newElemTypeSlice(new(genericType)), newElemTypeSlice(new(genericType))),
- )
- if err != nil {
- panic(err)
- }
- selectorFunc = func(item interface{}) interface{} {
- return selectorGenericFunc.Call(item)
- }
- }
- return oq.ThenByDescending(selectorFunc)
- }
- // 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
- }
- },
- }
- }
- // SortT is the typed version of Sort.
- // - lessFn is of type "func(TSource,TSource) bool"
- // NOTE: Sort has better performance than SortT.
- func (q Query) SortT(lessFn interface{}) Query {
- lessGenericFunc, err := newGenericFunc(
- "SortT", "lessFn", lessFn,
- simpleParamValidator(newElemTypeSlice(new(genericType), new(genericType)), newElemTypeSlice(new(bool))),
- )
- if err != nil {
- panic(err)
- }
- lessFunc := func(i, j interface{}) bool {
- return lessGenericFunc.Call(i, j).(bool)
- }
- return q.Sort(lessFunc)
- }
- 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)
- }
- if len(r) == 0 {
- return
- }
- 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
- }
|