213 lines
4.6 KiB
Go
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
|
|
}
|