File: multiKeySort.go

package info (click to toggle)
golang-github-shenwei356-util 0.5.5-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 232 kB
  • sloc: makefile: 2
file content (148 lines) | stat: -rw-r--r-- 3,147 bytes parent folder | download
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
147
148
package stringutil

import (
	"math"
	"strconv"
	"strings"
	"time"

	"github.com/araddon/dateparse"
	"github.com/shenwei356/natsort"
)

// SortType defines the sort type
type SortType struct {
	Index       int
	IgnoreCase  bool
	Natural     bool // natural order
	Number      bool
	Date        bool
	UserDefined bool
	Reverse     bool
	Levels      map[string]int
}

// MultiKeyStringSlice sort [][]string by multiple keys
type MultiKeyStringSlice struct {
	SortTypes *[]SortType
	Value     []string
}

// MultiKeyStringSliceList is slice of MultiKeyStringSlice
type MultiKeyStringSliceList []MultiKeyStringSlice

func (list MultiKeyStringSliceList) Len() int { return len(list) }
func (list MultiKeyStringSliceList) Swap(i, j int) {
	list[i], list[j] = list[j], list[i]
}

func (list MultiKeyStringSliceList) Less(i, j int) bool {
	var err, err2 error
	var v int
	var a, b int
	var okA, okB bool
	var ta, tb time.Time
	for _, t := range *list[i].SortTypes {
		if t.Natural {
			if t.IgnoreCase {
				v = strings.Compare(strings.ToLower(list[i].Value[t.Index]),
					strings.ToLower(list[j].Value[t.Index]))
			} else {
				v = strings.Compare(list[i].Value[t.Index], list[j].Value[t.Index])
			}
			if v == 0 {
				continue
			}

			if natsort.Compare(list[i].Value[t.Index], list[j].Value[t.Index], t.IgnoreCase) {
				v = -1
			} else {
				v = 1
			}
		} else if t.Number {
			var a, b float64
			a, err = strconv.ParseFloat(removeComma(list[i].Value[t.Index]), 64)
			if err != nil || math.IsNaN(a) {
				a = math.MaxFloat64
			}
			b, err = strconv.ParseFloat(removeComma(list[j].Value[t.Index]), 64)
			if err != nil || math.IsNaN(b) {
				b = math.MaxFloat64
			}
			if a < b {
				v = -1
			} else if a == b {
				v = 0
			} else {
				v = 1
			}
		} else if t.Date {
			ta, err = dateparse.ParseLocal(list[i].Value[t.Index])
			tb, err2 = dateparse.ParseLocal(list[j].Value[t.Index])
			if err != nil {
				if err2 != nil {
					v = -1
				} else {
					v = 1
				}
			} else if err2 != nil {
				v = -1
			}
			if ta.Before(tb) {
				v = -1
			} else if ta.Equal(tb) {
				v = 0
			} else {
				v = 1
			}
		} else if t.UserDefined {
			if t.IgnoreCase {
				a, okA = t.Levels[strings.ToLower(list[i].Value[t.Index])]
				b, okB = t.Levels[strings.ToLower(list[j].Value[t.Index])]
			} else {
				a, okA = t.Levels[list[i].Value[t.Index]]
				b, okB = t.Levels[list[j].Value[t.Index]]
			}
			if okA {
				if okB {
					if a < b {
						v = -1
					} else if a == b {
						v = 0
					} else {
						v = 1
					}
				} else {
					v = -1
				}
			} else if okB {
				v = 1
			} else {
				v = strings.Compare(list[i].Value[t.Index], list[j].Value[t.Index])
			}
		} else {
			if t.IgnoreCase {
				v = strings.Compare(strings.ToLower(list[i].Value[t.Index]),
					strings.ToLower(list[j].Value[t.Index]))
			} else {
				v = strings.Compare(list[i].Value[t.Index], list[j].Value[t.Index])
			}
		}

		if v == 0 {
		} else if v < 0 {
			return !t.Reverse
		} else {
			return t.Reverse
		}
	}
	return false
}

func removeComma(s string) string {
	if !strings.ContainsRune(s, ',') {
		return s
	}

	return strings.ReplaceAll(s, ",", "")
}