Files
Go-tool/vendor/github.com/ahmetalpbalkan/go-linq/orderby.go
T

213 lines
4.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
}
},
},
}
}
// 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
}
},
},
}
}
// 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
}
},
},
}
}
// 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
}
},
},
}
}
// 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
}
},
}
}
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)
}
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
}