github.com/songzhibin97/go-baseutils@v0.0.2-0.20240302024150-487d8ce9c082/base/bslice/sort_test.go (about) 1 // Copyright 2022 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package bslice 6 7 import ( 8 "math" 9 "math/rand" 10 "sort" 11 "strconv" 12 "strings" 13 "testing" 14 ) 15 16 var ints = [...]int{74, 59, 238, -784, 9845, 959, 905, 0, 0, 42, 7586, -5467984, 7586} 17 var float64s = [...]float64{74.3, 59.0, math.Inf(1), 238.2, -784.0, 2.3, math.Inf(-1), 9845.768, -959.7485, 905, 7.8, 7.8, 74.3, 59.0, math.Inf(1), 238.2, -784.0, 2.3} 18 var float64sWithNaNs = [...]float64{74.3, 59.0, math.Inf(1), 238.2, -784.0, 2.3, math.NaN(), math.NaN(), math.Inf(-1), 9845.768, -959.7485, 905, 7.8, 7.8} 19 var strs = [...]string{"", "Hello", "foo", "bar", "foo", "f00", "%*&^*&^&", "***"} 20 21 func TestSortIntSlice(t *testing.T) { 22 data := Clone(ints[:]) 23 Sort(data) 24 if !IsSorted(data) { 25 t.Errorf("sorted %v", ints) 26 t.Errorf(" got %v", data) 27 } 28 } 29 30 func TestSortFuncIntSlice(t *testing.T) { 31 data := Clone(ints[:]) 32 SortFunc(data, func(a, b int) bool { return a < b }) 33 if !IsSorted(data) { 34 t.Errorf("sorted %v", ints) 35 t.Errorf(" got %v", data) 36 } 37 } 38 39 func TestSortFloat64Slice(t *testing.T) { 40 data := Clone(float64s[:]) 41 Sort(data) 42 if !IsSorted(data) { 43 t.Errorf("sorted %v", float64s) 44 t.Errorf(" got %v", data) 45 } 46 } 47 48 func TestSortFloat64SliceWithNaNs(t *testing.T) { 49 data := float64sWithNaNs[:] 50 input := Clone(data) 51 52 // Make sure Sort doesn't panic when the slice contains NaNs. 53 Sort(data) 54 // Check whether the result is a permutation of the input. 55 sort.Float64s(data) 56 sort.Float64s(input) 57 for i, v := range input { 58 if data[i] != v && !(math.IsNaN(data[i]) && math.IsNaN(v)) { 59 t.Fatalf("the result is not a permutation of the input\ngot %v\nwant %v", data, input) 60 } 61 } 62 } 63 64 func TestSortStringSlice(t *testing.T) { 65 data := Clone(strs[:]) 66 Sort(data) 67 if !IsSorted(data) { 68 t.Errorf("sorted %v", strs) 69 t.Errorf(" got %v", data) 70 } 71 } 72 73 func TestSortLarge_Random(t *testing.T) { 74 n := 1000000 75 if testing.Short() { 76 n /= 100 77 } 78 data := make([]int, n) 79 for i := 0; i < len(data); i++ { 80 data[i] = rand.Intn(100) 81 } 82 if IsSorted(data) { 83 t.Fatalf("terrible rand.rand") 84 } 85 Sort(data) 86 if !IsSorted(data) { 87 t.Errorf("sort didn't sort - 1M ints") 88 } 89 } 90 91 type intPair struct { 92 a, b int 93 } 94 95 type intPairs []intPair 96 97 // Pairs compare on a only. 98 func intPairLess(x, y intPair) bool { 99 return x.a < y.a 100 } 101 102 // Record initial order in B. 103 func (d intPairs) initB() { 104 for i := range d { 105 d[i].b = i 106 } 107 } 108 109 // InOrder checks if a-equal elements were not reordered. 110 func (d intPairs) inOrder() bool { 111 lastA, lastB := -1, 0 112 for i := 0; i < len(d); i++ { 113 if lastA != d[i].a { 114 lastA = d[i].a 115 lastB = d[i].b 116 continue 117 } 118 if d[i].b <= lastB { 119 return false 120 } 121 lastB = d[i].b 122 } 123 return true 124 } 125 126 func TestStability(t *testing.T) { 127 n, m := 100000, 1000 128 if testing.Short() { 129 n, m = 1000, 100 130 } 131 data := make(intPairs, n) 132 133 // random distribution 134 for i := 0; i < len(data); i++ { 135 data[i].a = rand.Intn(m) 136 } 137 if IsSortedFunc(data, intPairLess) { 138 t.Fatalf("terrible rand.rand") 139 } 140 data.initB() 141 SortStableFunc(data, intPairLess) 142 if !IsSortedFunc(data, intPairLess) { 143 t.Errorf("Stable didn't sort %d ints", n) 144 } 145 if !data.inOrder() { 146 t.Errorf("Stable wasn't stable on %d ints", n) 147 } 148 149 // already sorted 150 data.initB() 151 SortStableFunc(data, intPairLess) 152 if !IsSortedFunc(data, intPairLess) { 153 t.Errorf("Stable shuffled sorted %d ints (order)", n) 154 } 155 if !data.inOrder() { 156 t.Errorf("Stable shuffled sorted %d ints (stability)", n) 157 } 158 159 // sorted reversed 160 for i := 0; i < len(data); i++ { 161 data[i].a = len(data) - i 162 } 163 data.initB() 164 SortStableFunc(data, intPairLess) 165 if !IsSortedFunc(data, intPairLess) { 166 t.Errorf("Stable didn't sort %d ints", n) 167 } 168 if !data.inOrder() { 169 t.Errorf("Stable wasn't stable on %d ints", n) 170 } 171 } 172 173 func TestBinarySearch(t *testing.T) { 174 str1 := []string{"foo"} 175 str2 := []string{"ab", "ca"} 176 str3 := []string{"mo", "qo", "vo"} 177 str4 := []string{"ab", "ad", "ca", "xy"} 178 179 // slice with repeating elements 180 strRepeats := []string{"ba", "ca", "da", "da", "da", "ka", "ma", "ma", "ta"} 181 182 // slice with all element equal 183 strSame := []string{"xx", "xx", "xx"} 184 185 tests := []struct { 186 data []string 187 target string 188 wantPos int 189 wantFound bool 190 }{ 191 {[]string{}, "foo", 0, false}, 192 {[]string{}, "", 0, false}, 193 194 {str1, "foo", 0, true}, 195 {str1, "bar", 0, false}, 196 {str1, "zx", 1, false}, 197 198 {str2, "aa", 0, false}, 199 {str2, "ab", 0, true}, 200 {str2, "ad", 1, false}, 201 {str2, "ca", 1, true}, 202 {str2, "ra", 2, false}, 203 204 {str3, "bb", 0, false}, 205 {str3, "mo", 0, true}, 206 {str3, "nb", 1, false}, 207 {str3, "qo", 1, true}, 208 {str3, "tr", 2, false}, 209 {str3, "vo", 2, true}, 210 {str3, "xr", 3, false}, 211 212 {str4, "aa", 0, false}, 213 {str4, "ab", 0, true}, 214 {str4, "ac", 1, false}, 215 {str4, "ad", 1, true}, 216 {str4, "ax", 2, false}, 217 {str4, "ca", 2, true}, 218 {str4, "cc", 3, false}, 219 {str4, "dd", 3, false}, 220 {str4, "xy", 3, true}, 221 {str4, "zz", 4, false}, 222 223 {strRepeats, "da", 2, true}, 224 {strRepeats, "db", 5, false}, 225 {strRepeats, "ma", 6, true}, 226 {strRepeats, "mb", 8, false}, 227 228 {strSame, "xx", 0, true}, 229 {strSame, "ab", 0, false}, 230 {strSame, "zz", 3, false}, 231 } 232 for _, tt := range tests { 233 t.Run(tt.target, func(t *testing.T) { 234 { 235 pos, found := BinarySearch(tt.data, tt.target) 236 if pos != tt.wantPos || found != tt.wantFound { 237 t.Errorf("BinarySearch got (%v, %v), want (%v, %v)", pos, found, tt.wantPos, tt.wantFound) 238 } 239 } 240 241 { 242 pos, found := BinarySearchFunc(tt.data, tt.target, strings.Compare) 243 if pos != tt.wantPos || found != tt.wantFound { 244 t.Errorf("BinarySearchFunc got (%v, %v), want (%v, %v)", pos, found, tt.wantPos, tt.wantFound) 245 } 246 } 247 }) 248 } 249 } 250 251 func TestBinarySearchInts(t *testing.T) { 252 data := []int{20, 30, 40, 50, 60, 70, 80, 90} 253 tests := []struct { 254 target int 255 wantPos int 256 wantFound bool 257 }{ 258 {20, 0, true}, 259 {23, 1, false}, 260 {43, 3, false}, 261 {80, 6, true}, 262 } 263 for _, tt := range tests { 264 t.Run(strconv.Itoa(tt.target), func(t *testing.T) { 265 { 266 pos, found := BinarySearch(data, tt.target) 267 if pos != tt.wantPos || found != tt.wantFound { 268 t.Errorf("BinarySearch got (%v, %v), want (%v, %v)", pos, found, tt.wantPos, tt.wantFound) 269 } 270 } 271 272 { 273 cmp := func(a, b int) int { 274 return a - b 275 } 276 pos, found := BinarySearchFunc(data, tt.target, cmp) 277 if pos != tt.wantPos || found != tt.wantFound { 278 t.Errorf("BinarySearchFunc got (%v, %v), want (%v, %v)", pos, found, tt.wantPos, tt.wantFound) 279 } 280 } 281 }) 282 } 283 } 284 285 func TestBinarySearchFunc(t *testing.T) { 286 data := []int{1, 10, 11, 2} // sorted lexicographically 287 cmp := func(a int, b string) int { 288 return strings.Compare(strconv.Itoa(a), b) 289 } 290 pos, found := BinarySearchFunc(data, "2", cmp) 291 if pos != 3 || !found { 292 t.Errorf("BinarySearchFunc(%v, %q, cmp) = %v, %v, want %v, %v", data, "2", pos, found, 3, true) 293 } 294 }