github.com/goki/ki@v1.1.11/kit/slices.go (about) 1 // Copyright (c) 2018, The GoKi 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 kit 6 7 import ( 8 "fmt" 9 "log" 10 "reflect" 11 "sort" 12 "strings" 13 "time" 14 15 "github.com/goki/ki/floats" 16 "github.com/goki/ki/ints" 17 ) 18 19 // This file contains helpful functions for dealing with slices, in the reflect 20 // system 21 22 // SliceElType returns the type of the elements for the given slice (which can be 23 // a pointer to a slice or a direct slice) -- just Elem() of slice type, but using 24 // this function makes it more explicit what is going on. And it uses 25 // OnePtrUnderlyingValue to get past any interface wrapping. 26 func SliceElType(sl interface{}) reflect.Type { 27 return NonPtrValue(OnePtrUnderlyingValue(reflect.ValueOf(sl))).Type().Elem() 28 } 29 30 // SliceNewAt inserts a new blank element at given index in the slice -- -1 31 // means the end 32 func SliceNewAt(sl interface{}, idx int) { 33 sltyp := SliceElType(sl) 34 slptr := sltyp.Kind() == reflect.Ptr 35 36 svl := reflect.ValueOf(sl) 37 svnp := NonPtrValue(svl) 38 39 nval := reflect.New(NonPtrType(sltyp)) // make the concrete el 40 if !slptr { 41 nval = nval.Elem() // use concrete value 42 } 43 sz := svnp.Len() 44 svnp = reflect.Append(svnp, nval) 45 if idx >= 0 && idx < sz { 46 reflect.Copy(svnp.Slice(idx+1, sz+1), svnp.Slice(idx, sz)) 47 svnp.Index(idx).Set(nval) 48 } 49 svl.Elem().Set(svnp) 50 } 51 52 // SliceDeleteAt deletes element at given index from slice 53 func SliceDeleteAt(sl interface{}, idx int) { 54 svl := reflect.ValueOf(sl) 55 svnp := NonPtrValue(svl) 56 svtyp := svnp.Type() 57 nval := reflect.New(svtyp.Elem()) 58 sz := svnp.Len() 59 reflect.Copy(svnp.Slice(idx, sz-1), svnp.Slice(idx+1, sz)) 60 svnp.Index(sz - 1).Set(nval.Elem()) 61 svl.Elem().Set(svnp.Slice(0, sz-1)) 62 } 63 64 // SliceSort sorts a slice of basic values (see StructSliceSort for sorting a 65 // slice-of-struct using a specific field), trying floats.Floater Float(), 66 // ints.Inter Int(), interfaces first, and then falling back on reflect.Kind 67 // float, int, string conversions (first fmt.Stringer String()) and supporting 68 // time.Time directly as well. 69 func SliceSort(sl interface{}, ascending bool) error { 70 sv := reflect.ValueOf(sl) 71 svnp := NonPtrValue(sv) 72 if svnp.Len() == 0 { 73 return nil 74 } 75 eltyp := SliceElType(sl) 76 elnptyp := NonPtrType(eltyp) 77 vk := elnptyp.Kind() 78 elval := OnePtrValue(svnp.Index(0)) 79 elif := elval.Interface() 80 81 switch elif.(type) { 82 case floats.Floater: 83 sort.Slice(svnp.Interface(), func(i, j int) bool { 84 iv := NonPtrValue(svnp.Index(i)).Interface().(floats.Floater).Float() 85 jv := NonPtrValue(svnp.Index(j)).Interface().(floats.Floater).Float() 86 if ascending { 87 return iv < jv 88 } 89 return iv > jv 90 }) 91 return nil 92 case ints.Inter: 93 sort.Slice(svnp.Interface(), func(i, j int) bool { 94 iv := NonPtrValue(svnp.Index(i)).Interface().(ints.Inter).Int() 95 jv := NonPtrValue(svnp.Index(j)).Interface().(ints.Inter).Int() 96 if ascending { 97 return iv < jv 98 } 99 return iv > jv 100 }) 101 return nil 102 } 103 104 // try all the numeric types first! 105 106 switch { 107 case vk >= reflect.Int && vk <= reflect.Int64: 108 sort.Slice(svnp.Interface(), func(i, j int) bool { 109 iv := NonPtrValue(svnp.Index(i)).Int() 110 jv := NonPtrValue(svnp.Index(j)).Int() 111 if ascending { 112 return iv < jv 113 } 114 return iv > jv 115 }) 116 return nil 117 case vk >= reflect.Uint && vk <= reflect.Uint64: 118 sort.Slice(svnp.Interface(), func(i, j int) bool { 119 iv := NonPtrValue(svnp.Index(i)).Uint() 120 jv := NonPtrValue(svnp.Index(j)).Uint() 121 if ascending { 122 return iv < jv 123 } 124 return iv > jv 125 }) 126 return nil 127 case vk >= reflect.Float32 && vk <= reflect.Float64: 128 sort.Slice(svnp.Interface(), func(i, j int) bool { 129 iv := NonPtrValue(svnp.Index(i)).Float() 130 jv := NonPtrValue(svnp.Index(j)).Float() 131 if ascending { 132 return iv < jv 133 } 134 return iv > jv 135 }) 136 return nil 137 case vk == reflect.Struct && ShortTypeName(elnptyp) == "time.Time": 138 sort.Slice(svnp.Interface(), func(i, j int) bool { 139 iv := NonPtrValue(svnp.Index(i)).Interface().(time.Time) 140 jv := NonPtrValue(svnp.Index(j)).Interface().(time.Time) 141 if ascending { 142 return iv.Before(jv) 143 } 144 return jv.Before(iv) 145 }) 146 } 147 148 // this stringer case will likely pick up most of the rest 149 switch elif.(type) { 150 case fmt.Stringer: 151 sort.Slice(svnp.Interface(), func(i, j int) bool { 152 iv := NonPtrValue(svnp.Index(i)).Interface().(fmt.Stringer).String() 153 jv := NonPtrValue(svnp.Index(j)).Interface().(fmt.Stringer).String() 154 if ascending { 155 return iv < jv 156 } 157 return iv > jv 158 }) 159 return nil 160 } 161 162 // last resort! 163 switch { 164 case vk == reflect.String: 165 sort.Slice(svnp.Interface(), func(i, j int) bool { 166 iv := NonPtrValue(svnp.Index(i)).String() 167 jv := NonPtrValue(svnp.Index(j)).String() 168 if ascending { 169 return strings.ToLower(iv) < strings.ToLower(jv) 170 } 171 return strings.ToLower(iv) > strings.ToLower(jv) 172 }) 173 return nil 174 } 175 176 err := fmt.Errorf("SortSlice: unable to sort elements of type: %v", eltyp.String()) 177 log.Println(err) 178 return err 179 } 180 181 // StructSliceSort sorts a slice of a struct according to the given field 182 // indexes and sort direction, trying floats.Floater Float(), ints.Inter Int(), 183 // interfaces first, and then falling back on reflect.Kind float, int, string 184 // conversions (first fmt.Stringer String()) and supporting time.Time directly 185 // as well. There is no direct method for checking the field indexes so those 186 // are assumed to be accurate -- will panic if not! 187 func StructSliceSort(struSlice interface{}, fldIdx []int, ascending bool) error { 188 sv := reflect.ValueOf(struSlice) 189 svnp := NonPtrValue(sv) 190 if svnp.Len() == 0 { 191 return nil 192 } 193 struTyp := SliceElType(struSlice) 194 struNpTyp := NonPtrType(struTyp) 195 fld := struNpTyp.FieldByIndex(fldIdx) // not easy to check. 196 vk := fld.Type.Kind() 197 struVal := OnePtrValue(svnp.Index(0)) 198 fldVal := struVal.Elem().FieldByIndex(fldIdx) 199 fldIf := fldVal.Interface() 200 201 switch fldIf.(type) { 202 case floats.Floater: 203 sort.Slice(svnp.Interface(), func(i, j int) bool { 204 ival := OnePtrValue(svnp.Index(i)) 205 iv := ival.Elem().FieldByIndex(fldIdx).Interface().(floats.Floater).Float() 206 jval := OnePtrValue(svnp.Index(j)) 207 jv := jval.Elem().FieldByIndex(fldIdx).Interface().(floats.Floater).Float() 208 if ascending { 209 return iv < jv 210 } 211 return iv > jv 212 }) 213 return nil 214 case ints.Inter: 215 sort.Slice(svnp.Interface(), func(i, j int) bool { 216 ival := OnePtrValue(svnp.Index(i)) 217 iv := ival.Elem().FieldByIndex(fldIdx).Interface().(ints.Inter).Int() 218 jval := OnePtrValue(svnp.Index(j)) 219 jv := jval.Elem().FieldByIndex(fldIdx).Interface().(ints.Inter).Int() 220 if ascending { 221 return iv < jv 222 } 223 return iv > jv 224 }) 225 return nil 226 } 227 228 // try all the numeric types first! 229 230 switch { 231 case vk >= reflect.Int && vk <= reflect.Int64: 232 sort.Slice(svnp.Interface(), func(i, j int) bool { 233 ival := OnePtrValue(svnp.Index(i)) 234 iv := ival.Elem().FieldByIndex(fldIdx).Int() 235 jval := OnePtrValue(svnp.Index(j)) 236 jv := jval.Elem().FieldByIndex(fldIdx).Int() 237 if ascending { 238 return iv < jv 239 } 240 return iv > jv 241 }) 242 return nil 243 case vk >= reflect.Uint && vk <= reflect.Uint64: 244 sort.Slice(svnp.Interface(), func(i, j int) bool { 245 ival := OnePtrValue(svnp.Index(i)) 246 iv := ival.Elem().FieldByIndex(fldIdx).Uint() 247 jval := OnePtrValue(svnp.Index(j)) 248 jv := jval.Elem().FieldByIndex(fldIdx).Uint() 249 if ascending { 250 return iv < jv 251 } 252 return iv > jv 253 }) 254 return nil 255 case vk >= reflect.Float32 && vk <= reflect.Float64: 256 sort.Slice(svnp.Interface(), func(i, j int) bool { 257 ival := OnePtrValue(svnp.Index(i)) 258 iv := ival.Elem().FieldByIndex(fldIdx).Float() 259 jval := OnePtrValue(svnp.Index(j)) 260 jv := jval.Elem().FieldByIndex(fldIdx).Float() 261 if ascending { 262 return iv < jv 263 } 264 return iv > jv 265 }) 266 return nil 267 case vk == reflect.Struct && ShortTypeName(fld.Type) == "time.Time": 268 sort.Slice(svnp.Interface(), func(i, j int) bool { 269 ival := OnePtrValue(svnp.Index(i)) 270 iv := ival.Elem().FieldByIndex(fldIdx).Interface().(time.Time) 271 jval := OnePtrValue(svnp.Index(j)) 272 jv := jval.Elem().FieldByIndex(fldIdx).Interface().(time.Time) 273 if ascending { 274 return iv.Before(jv) 275 } 276 return jv.Before(iv) 277 }) 278 } 279 280 // this stringer case will likely pick up most of the rest 281 switch fldIf.(type) { 282 case fmt.Stringer: 283 sort.Slice(svnp.Interface(), func(i, j int) bool { 284 ival := OnePtrValue(svnp.Index(i)) 285 iv := ival.Elem().FieldByIndex(fldIdx).Interface().(fmt.Stringer).String() 286 jval := OnePtrValue(svnp.Index(j)) 287 jv := jval.Elem().FieldByIndex(fldIdx).Interface().(fmt.Stringer).String() 288 if ascending { 289 return iv < jv 290 } 291 return iv > jv 292 }) 293 return nil 294 } 295 296 // last resort! 297 switch { 298 case vk == reflect.String: 299 sort.Slice(svnp.Interface(), func(i, j int) bool { 300 ival := OnePtrValue(svnp.Index(i)) 301 iv := ival.Elem().FieldByIndex(fldIdx).String() 302 jval := OnePtrValue(svnp.Index(j)) 303 jv := jval.Elem().FieldByIndex(fldIdx).String() 304 if ascending { 305 return strings.ToLower(iv) < strings.ToLower(jv) 306 } 307 return strings.ToLower(iv) > strings.ToLower(jv) 308 }) 309 return nil 310 } 311 312 err := fmt.Errorf("SortStructSlice: unable to sort on field of type: %v\n", fld.Type.String()) 313 log.Println(err) 314 return err 315 } 316 317 // ValueSliceSort sorts a slice of reflect.Values using basic types where possible 318 func ValueSliceSort(sl []reflect.Value, ascending bool) error { 319 if len(sl) == 0 { 320 return nil 321 } 322 felval := sl[0] // reflect.Value 323 eltyp := felval.Type() 324 elnptyp := NonPtrType(eltyp) 325 vk := elnptyp.Kind() 326 elval := OnePtrValue(felval) 327 elif := elval.Interface() 328 329 switch elif.(type) { 330 case floats.Floater: 331 sort.Slice(sl, func(i, j int) bool { 332 iv := NonPtrValue(sl[i]).Interface().(floats.Floater).Float() 333 jv := NonPtrValue(sl[j]).Interface().(floats.Floater).Float() 334 if ascending { 335 return iv < jv 336 } 337 return iv > jv 338 }) 339 return nil 340 case ints.Inter: 341 sort.Slice(sl, func(i, j int) bool { 342 iv := NonPtrValue(sl[i]).Interface().(ints.Inter).Int() 343 jv := NonPtrValue(sl[j]).Interface().(ints.Inter).Int() 344 if ascending { 345 return iv < jv 346 } 347 return iv > jv 348 }) 349 return nil 350 } 351 352 // try all the numeric types first! 353 354 switch { 355 case vk >= reflect.Int && vk <= reflect.Int64: 356 sort.Slice(sl, func(i, j int) bool { 357 iv := NonPtrValue(sl[i]).Int() 358 jv := NonPtrValue(sl[j]).Int() 359 if ascending { 360 return iv < jv 361 } 362 return iv > jv 363 }) 364 return nil 365 case vk >= reflect.Uint && vk <= reflect.Uint64: 366 sort.Slice(sl, func(i, j int) bool { 367 iv := NonPtrValue(sl[i]).Uint() 368 jv := NonPtrValue(sl[j]).Uint() 369 if ascending { 370 return iv < jv 371 } 372 return iv > jv 373 }) 374 return nil 375 case vk >= reflect.Float32 && vk <= reflect.Float64: 376 sort.Slice(sl, func(i, j int) bool { 377 iv := NonPtrValue(sl[i]).Float() 378 jv := NonPtrValue(sl[j]).Float() 379 if ascending { 380 return iv < jv 381 } 382 return iv > jv 383 }) 384 return nil 385 case vk == reflect.Struct && ShortTypeName(elnptyp) == "time.Time": 386 sort.Slice(sl, func(i, j int) bool { 387 iv := NonPtrValue(sl[i]).Interface().(time.Time) 388 jv := NonPtrValue(sl[j]).Interface().(time.Time) 389 if ascending { 390 return iv.Before(jv) 391 } 392 return jv.Before(iv) 393 }) 394 } 395 396 // this stringer case will likely pick up most of the rest 397 switch elif.(type) { 398 case fmt.Stringer: 399 sort.Slice(sl, func(i, j int) bool { 400 iv := NonPtrValue(sl[i]).Interface().(fmt.Stringer).String() 401 jv := NonPtrValue(sl[j]).Interface().(fmt.Stringer).String() 402 if ascending { 403 return iv < jv 404 } 405 return iv > jv 406 }) 407 return nil 408 } 409 410 // last resort! 411 switch { 412 case vk == reflect.String: 413 sort.Slice(sl, func(i, j int) bool { 414 iv := NonPtrValue(sl[i]).String() 415 jv := NonPtrValue(sl[j]).String() 416 if ascending { 417 return strings.ToLower(iv) < strings.ToLower(jv) 418 } 419 return strings.ToLower(iv) > strings.ToLower(jv) 420 }) 421 return nil 422 } 423 424 err := fmt.Errorf("ValueSliceSort: unable to sort elements of type: %v", eltyp.String()) 425 log.Println(err) 426 return err 427 }