Files
Go-http_framework/vendor/github.com/ahmetb/go-linq/orderby.go
T

314 lines
7.6 KiB
Go

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
}
},
},
}
}
// 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
}