-
-
Notifications
You must be signed in to change notification settings - Fork 95
/
sort.go
146 lines (116 loc) · 2.81 KB
/
sort.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
// Copyright 2018-20 PJ Engineering and Business Solutions Pty. Ltd. All rights reserved.
package dataframe
import (
"context"
"sort"
)
// IsEqualFunc is used to determine if a and b are considered equal.
type IsEqualFunc func(a, b interface{}) bool
// IsLessThanFunc returns true if a < b
type IsLessThanFunc func(a, b interface{}) bool
// SortKey is the key to sort a Dataframe
type SortKey struct {
// Key can be an int (position of series) or string (name of series).
Key interface{}
// Desc can be set to sort in descending order.
Desc bool
seriesIndex int
}
type sorter struct {
keys []SortKey
df *DataFrame
ctx context.Context
}
func (s *sorter) Len() int {
return s.df.n
}
func (s *sorter) Less(i, j int) bool {
if err := s.ctx.Err(); err != nil {
panic(err)
}
for _, key := range s.keys {
series := s.df.Series[key.seriesIndex]
left := series.Value(i)
right := series.Value(j)
// Check if left and right are equal
if series.IsEqualFunc(left, right) {
continue
} else {
if key.Desc {
// Sort in descending order
return !series.IsLessThanFunc(left, right)
}
return series.IsLessThanFunc(left, right)
}
}
return false
}
func (s *sorter) Swap(i, j int) {
s.df.Swap(i, j, DontLock)
}
// SortOptions is used to configure the sort algorithm for a Dataframe or Series
type SortOptions struct {
// Stable can be set if the original order of equal items must be maintained.
//
// See: https://golang.org/pkg/sort/#Stable
Stable bool
// Desc can be set to sort in descending order. This option is ignored when applied to a Dataframe.
// Only use it with a Series.
Desc bool
// DontLock can be set to true if the Series should not be locked.
DontLock bool
}
// Sort is used to sort the Dataframe according to different keys.
// It will return true if sorting was completed or false when the context is canceled.
func (df *DataFrame) Sort(ctx context.Context, keys []SortKey, opts ...SortOptions) (completed bool) {
if len(keys) == 0 {
return true
}
defer func() {
if x := recover(); x != nil {
if x == context.Canceled || x == context.DeadlineExceeded {
completed = false
} else {
panic(x)
}
}
}()
if len(opts) == 0 || !opts[0].DontLock {
// Default
df.lock.Lock()
defer df.lock.Unlock()
}
// Clear seriesIndex from keys
defer func() {
for i := range keys {
key := &keys[i]
key.seriesIndex = 0
}
}()
// Convert keys to index
for i := range keys {
key := &keys[i]
name, ok := key.Key.(string)
if ok {
col, err := df.NameToColumn(name, dontLock)
if err != nil {
panic(err)
}
key.seriesIndex = col
} else {
key.seriesIndex = key.Key.(int)
}
}
s := &sorter{
keys: keys,
df: df,
ctx: ctx,
}
if len(opts) == 0 || !opts[0].Stable {
// Default
sort.Sort(s)
} else {
sort.Stable(s)
}
return true
}