github.com/wangyougui/gf/v2@v2.6.5/util/gutil/gutil_list.go (about) 1 // Copyright GoFrame Author(https://goframe.org). All Rights Reserved. 2 // 3 // This Source Code Form is subject to the terms of the MIT License. 4 // If a copy of the MIT was not distributed with this file, 5 // You can obtain one at https://github.com/wangyougui/gf. 6 7 package gutil 8 9 import ( 10 "reflect" 11 12 "github.com/wangyougui/gf/v2/internal/utils" 13 ) 14 15 // ListItemValues retrieves and returns the elements of all item struct/map with key `key`. 16 // Note that the parameter `list` should be type of slice which contains elements of map or struct, 17 // or else it returns an empty slice. 18 // 19 // The parameter `list` supports types like: 20 // []map[string]interface{} 21 // []map[string]sub-map 22 // []struct 23 // []struct:sub-struct 24 // Note that the sub-map/sub-struct makes sense only if the optional parameter `subKey` is given. 25 func ListItemValues(list interface{}, key interface{}, subKey ...interface{}) (values []interface{}) { 26 var reflectValue reflect.Value 27 if v, ok := list.(reflect.Value); ok { 28 reflectValue = v 29 } else { 30 reflectValue = reflect.ValueOf(list) 31 } 32 reflectKind := reflectValue.Kind() 33 for reflectKind == reflect.Ptr { 34 reflectValue = reflectValue.Elem() 35 reflectKind = reflectValue.Kind() 36 } 37 switch reflectKind { 38 case reflect.Slice, reflect.Array: 39 if reflectValue.Len() == 0 { 40 return 41 } 42 values = []interface{}{} 43 for i := 0; i < reflectValue.Len(); i++ { 44 if value, ok := ItemValue(reflectValue.Index(i), key); ok { 45 if len(subKey) > 0 && subKey[0] != nil { 46 if subValue, ok := ItemValue(value, subKey[0]); ok { 47 value = subValue 48 } else { 49 continue 50 } 51 } 52 if array, ok := value.([]interface{}); ok { 53 values = append(values, array...) 54 } else { 55 values = append(values, value) 56 } 57 } 58 } 59 } 60 return 61 } 62 63 // ItemValue retrieves and returns its value of which name/attribute specified by `key`. 64 // The parameter `item` can be type of map/*map/struct/*struct. 65 func ItemValue(item interface{}, key interface{}) (value interface{}, found bool) { 66 var reflectValue reflect.Value 67 if v, ok := item.(reflect.Value); ok { 68 reflectValue = v 69 } else { 70 reflectValue = reflect.ValueOf(item) 71 } 72 reflectKind := reflectValue.Kind() 73 if reflectKind == reflect.Interface { 74 reflectValue = reflectValue.Elem() 75 reflectKind = reflectValue.Kind() 76 } 77 for reflectKind == reflect.Ptr { 78 reflectValue = reflectValue.Elem() 79 reflectKind = reflectValue.Kind() 80 } 81 var keyValue reflect.Value 82 if v, ok := key.(reflect.Value); ok { 83 keyValue = v 84 } else { 85 keyValue = reflect.ValueOf(key) 86 } 87 switch reflectKind { 88 case reflect.Array, reflect.Slice: 89 // The `key` must be type of string. 90 values := ListItemValues(reflectValue, keyValue.String()) 91 if values == nil { 92 return nil, false 93 } 94 return values, true 95 96 case reflect.Map: 97 v := reflectValue.MapIndex(keyValue) 98 if v.IsValid() { 99 found = true 100 value = v.Interface() 101 } 102 103 case reflect.Struct: 104 // The `mapKey` must be type of string. 105 v := reflectValue.FieldByName(keyValue.String()) 106 if v.IsValid() { 107 found = true 108 value = v.Interface() 109 } 110 } 111 return 112 } 113 114 // ListItemValuesUnique retrieves and returns the unique elements of all struct/map with key `key`. 115 // Note that the parameter `list` should be type of slice which contains elements of map or struct, 116 // or else it returns an empty slice. 117 func ListItemValuesUnique(list interface{}, key string, subKey ...interface{}) []interface{} { 118 values := ListItemValues(list, key, subKey...) 119 if len(values) > 0 { 120 var ( 121 ok bool 122 m = make(map[interface{}]struct{}, len(values)) 123 ) 124 for i := 0; i < len(values); { 125 value := values[i] 126 if t, ok := value.([]byte); ok { 127 // make byte slice comparable 128 value = string(t) 129 } 130 if _, ok = m[value]; ok { 131 values = SliceDelete(values, i) 132 } else { 133 m[value] = struct{}{} 134 i++ 135 } 136 } 137 } 138 return values 139 } 140 141 // ListToMapByKey converts `list` to a map[string]interface{} of which key is specified by `key`. 142 // Note that the item value may be type of slice. 143 func ListToMapByKey(list []map[string]interface{}, key string) map[string]interface{} { 144 return utils.ListToMapByKey(list, key) 145 }