1、背景
后端返回 List
列表中的 Json
序列化结构到前端,其中包含许多字段,业务需求可以按照某个字段对列表数据做 升/降序排序。
2、代码实现
前端将后端返回的 Json
关键字及排序方向作为参数传递至后端即可,后端根据 Json
排序关键字找到对应的 JsonTag
后,采用反射找到字段,再写自定义排序函数即可实现指定字段的排序。
Go 代码:文章来源:https://www.toymoban.com/news/detail-533366.html
func SliceSortByJsonTag(slice interface{}, tagName string, ascending bool) {
value := reflect.ValueOf(slice)
typ := value.Type().Elem()
// 匹配不到指定的 jsonTag 则不进行排序
if name := getFieldName(typ, tagName); len(name) > 0 {
sort.SliceStable(slice, func(i, j int) bool {
fieldI := value.Index(i).FieldByName(name)
fieldJ := value.Index(j).FieldByName(name)
switch fieldI.Kind() {
case reflect.String:
if ascending {
return fieldI.String() < fieldJ.String()
} else {
return fieldI.String() > fieldJ.String()
}
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
if ascending {
return fieldI.Int() < fieldJ.Int()
} else {
return fieldI.Int() > fieldJ.Int()
}
case reflect.Float32, reflect.Float64:
if ascending {
return fieldI.Float() < fieldJ.Float()
} else {
return fieldI.Float() > fieldJ.Float()
}
default:
return false
}
})
}
}
func getFieldName(typ reflect.Type, tagName string) string {
for i := 0; i < typ.NumField(); i++ {
field := typ.Field(i)
if field.Tag.Get("json") == tagName {
return field.Name
}
}
return ""
}
单元测试:文章来源地址https://www.toymoban.com/news/detail-533366.html
type Person struct {
Name string `json:"name"`
Age int `json:"age"`
Gender string `json:"gender"`
}
func TestSliceSortByJsonTag(t *testing.T) {
tests := []struct {
name string
persons []Person
tagName string
ascending bool
expectedOrder []Person
}{
{
name: "按姓名升序排序",
persons: []Person{
{Name: "Bob", Age: 30, Gender: "male"},
{Name: "Alice", Age: 25, Gender: "female"},
{Name: "Charlie", Age: 20, Gender: "male"},
},
tagName: "name",
ascending: true,
expectedOrder: []Person{
{Name: "Alice", Age: 25, Gender: "female"},
{Name: "Bob", Age: 30, Gender: "male"},
{Name: "Charlie", Age: 20, Gender: "male"},
},
},
{
name: "按年龄降序排序",
persons: []Person{
{Name: "Bob", Age: 30, Gender: "male"},
{Name: "Alice", Age: 25, Gender: "female"},
{Name: "Charlie", Age: 20, Gender: "male"},
},
tagName: "age",
ascending: false,
expectedOrder: []Person{
{Name: "Bob", Age: 30, Gender: "male"},
{Name: "Alice", Age: 25, Gender: "female"},
{Name: "Charlie", Age: 20, Gender: "male"},
},
},
{
name: "按性别升序排序",
persons: []Person{
{Name: "Bob", Age: 30, Gender: "male"},
{Name: "Alice", Age: 25, Gender: "female"},
{Name: "Charlie", Age: 20, Gender: "male"},
},
tagName: "gender",
ascending: true,
expectedOrder: []Person{
{Name: "Alice", Age: 25, Gender: "female"},
{Name: "Bob", Age: 30, Gender: "male"},
{Name: "Charlie", Age: 20, Gender: "male"},
},
},
{
name: "未匹配到指定tag,不进行排序",
persons: []Person{
{Name: "Bob", Age: 30, Gender: "male"},
{Name: "Alice", Age: 25, Gender: "female"},
{Name: "Charlie", Age: 20, Gender: "male"},
},
tagName: "xxxx",
ascending: true,
expectedOrder: []Person{
{Name: "Bob", Age: 30, Gender: "male"},
{Name: "Alice", Age: 25, Gender: "female"},
{Name: "Charlie", Age: 20, Gender: "male"},
},
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
persons := make([]Person, len(test.persons))
copy(persons, test.persons)
SliceSortByJsonTag(persons, test.tagName, test.ascending)
if !reflect.DeepEqual(persons, test.expectedOrder) {
t.Errorf("Sorting failed.\nExpected: %v\nGot: %v", test.expectedOrder, persons)
}
})
}
}
3、工具改进
- 可考虑支持
Json
嵌套结构的排序 - 支持更多数据类型
到了这里,关于【GoLang】【工具分享】1、根据 JsonTag 对 slice 进行稳定排序(不支持嵌套)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!