github.com/aarzilli/tools@v0.0.0-20151123112009-0d27094f75e0/sort/subsort/precursor_ideas_test.go (about) 1 package subsort 2 3 // File contains examples of other strategies for flexible sorting. 4 // I considered and rejected these examples. 5 // Then I developed my own versatile sorting helper. 6 7 import ( 8 "fmt" 9 "reflect" 10 "sort" 11 "testing" 12 ) 13 14 //-------------------------------------------- 15 // Precursor 1 16 17 // A type, containing function headers for the sort interface. 18 type sortI struct { 19 l int // not len(), but its value 20 less func(int, int) bool 21 swap func(int, int) 22 } 23 24 // The methods of the sort interface 25 // are now satisfied, using the *members* of the struct. 26 func (s *sortI) Len() int { 27 return s.l 28 } 29 30 func (s *sortI) Less(i, j int) bool { 31 return s.less(i, j) 32 } 33 34 func (s *sortI) Swap(i, j int) { 35 s.swap(i, j) 36 } 37 38 // SortI can now be used as follows: 39 // sort.Sort( &sortI{} ) 40 41 // SortF wraps the construction 42 // and usage of a sortI instance. 43 func SortF(Len int, Less func(int, int) bool, Swap func(int, int)) { 44 si := &sortI{l: Len, less: Less, swap: Swap} 45 sort.Sort(si) 46 } 47 48 // We can now take any int slice 49 // and construct two-and-a-half closures with it 50 // and pass the closures (with our int slice implicitly piggypacked) to SortF 51 func TestSortI_demo(t *testing.T) { 52 ints := []int{3, 4, 1, 7, 0} 53 SortF(len(ints), func(i, j int) bool { 54 return ints[i] < ints[j] 55 }, func(i, j int) { 56 ints[i], ints[j] = ints[j], ints[i] 57 }) 58 want := fmt.Sprintf("%#v", []int{0, 1, 3, 4, 7}) 59 got := fmt.Sprintf("%#v", ints) 60 if want != got { 61 t.Errorf("wanted vs got: \n%v \n%v", want, got) 62 } 63 } 64 65 // This approach still needs typespecific variations of sortI. 66 // And it requires the closure notation. 67 68 // 69 //-------------------------------------------- 70 71 // precursor2 - using interface{} 72 // copyAndSort() first produces a copy, 73 // the copy containing only the desired data. 74 // Then this subset copy is sorted. 75 // Sadly, the argument of type []interface{} is expensive to create 76 // from calling packages. It mostly involves previous copying element by element 77 // thus genericism causes *two* rounds of copying. 78 // For this reason we prefer the SortByVal() func, 79 // width the only downside, that the preparation of the subset slice 80 // needs to be done by the calling package. 81 // Otherwise we are left with only *one* round of copying 82 // and without the need for reflection. 83 func demo__copyAndSort(sArg []interface{}, fieldname string) []SortedByStringVal { 84 85 copyOfSubset := []SortedByStringVal{} 86 for i := 0; i < len(sArg); i++ { 87 lp := sArg[i] 88 immutable := reflect.ValueOf(lp) 89 // reflect.Value.String() does not panic upon non-strings. 90 // Instead it returns "<type value>" for non-string 91 dynVal := immutable.FieldByName(fieldname).String() 92 copyOfSubset = append(copyOfSubset, SortedByStringVal{IdxOrig: i, Val: dynVal}) 93 } 94 95 wrapperSortable := sliceSortableStringAsc(copyOfSubset) 96 sort.Sort(wrapperSortable) 97 unwrap := []SortedByStringVal(wrapperSortable) 98 return unwrap 99 100 } 101 102 // 103 // 104 func demo__GetFieldValueByName() { 105 type MyStruct struct { 106 SortBy string 107 } 108 myStruct := MyStruct{"001"} 109 immutable := reflect.ValueOf(myStruct) 110 val := immutable.FieldByName("SortBy").String() 111 _ = val 112 }