github.com/gogf/gf@v1.16.9/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/gogf/gf. 6 7 package gutil 8 9 import ( 10 "reflect" 11 ) 12 13 // ListItemValues retrieves and returns the elements of all item struct/map with key `key`. 14 // Note that the parameter `list` should be type of slice which contains elements of map or struct, 15 // or else it returns an empty slice. 16 // 17 // The parameter `list` supports types like: 18 // []map[string]interface{} 19 // []map[string]sub-map 20 // []struct 21 // []struct:sub-struct 22 // Note that the sub-map/sub-struct makes sense only if the optional parameter `subKey` is given. 23 func ListItemValues(list interface{}, key interface{}, subKey ...interface{}) (values []interface{}) { 24 var reflectValue reflect.Value 25 if v, ok := list.(reflect.Value); ok { 26 reflectValue = v 27 } else { 28 reflectValue = reflect.ValueOf(list) 29 } 30 reflectKind := reflectValue.Kind() 31 for reflectKind == reflect.Ptr { 32 reflectValue = reflectValue.Elem() 33 reflectKind = reflectValue.Kind() 34 } 35 switch reflectKind { 36 case reflect.Slice, reflect.Array: 37 if reflectValue.Len() == 0 { 38 return 39 } 40 values = []interface{}{} 41 for i := 0; i < reflectValue.Len(); i++ { 42 if value, ok := ItemValue(reflectValue.Index(i), key); ok { 43 if len(subKey) > 0 && subKey[0] != nil { 44 if subValue, ok := ItemValue(value, subKey[0]); ok { 45 value = subValue 46 } else { 47 continue 48 } 49 } 50 if array, ok := value.([]interface{}); ok { 51 values = append(values, array...) 52 } else { 53 values = append(values, value) 54 } 55 } 56 } 57 } 58 return 59 } 60 61 // ItemValue retrieves and returns its value of which name/attribute specified by `key`. 62 // The parameter `item` can be type of map/*map/struct/*struct. 63 func ItemValue(item interface{}, key interface{}) (value interface{}, found bool) { 64 var reflectValue reflect.Value 65 if v, ok := item.(reflect.Value); ok { 66 reflectValue = v 67 } else { 68 reflectValue = reflect.ValueOf(item) 69 } 70 reflectKind := reflectValue.Kind() 71 if reflectKind == reflect.Interface { 72 reflectValue = reflectValue.Elem() 73 reflectKind = reflectValue.Kind() 74 } 75 for reflectKind == reflect.Ptr { 76 reflectValue = reflectValue.Elem() 77 reflectKind = reflectValue.Kind() 78 } 79 var keyValue reflect.Value 80 if v, ok := key.(reflect.Value); ok { 81 keyValue = v 82 } else { 83 keyValue = reflect.ValueOf(key) 84 } 85 switch reflectKind { 86 case reflect.Array, reflect.Slice: 87 // The `key` must be type of string. 88 values := ListItemValues(reflectValue, keyValue.String()) 89 if values == nil { 90 return nil, false 91 } 92 return values, true 93 94 case reflect.Map: 95 v := reflectValue.MapIndex(keyValue) 96 if v.IsValid() { 97 found = true 98 value = v.Interface() 99 } 100 101 case reflect.Struct: 102 // The `mapKey` must be type of string. 103 v := reflectValue.FieldByName(keyValue.String()) 104 if v.IsValid() { 105 found = true 106 value = v.Interface() 107 } 108 } 109 return 110 } 111 112 // ListItemValuesUnique retrieves and returns the unique elements of all struct/map with key `key`. 113 // Note that the parameter `list` should be type of slice which contains elements of map or struct, 114 // or else it returns an empty slice. 115 func ListItemValuesUnique(list interface{}, key string, subKey ...interface{}) []interface{} { 116 values := ListItemValues(list, key, subKey...) 117 if len(values) > 0 { 118 var ( 119 ok bool 120 m = make(map[interface{}]struct{}, len(values)) 121 ) 122 for i := 0; i < len(values); { 123 if _, ok = m[values[i]]; ok { 124 values = SliceDelete(values, i) 125 } else { 126 m[values[i]] = struct{}{} 127 i++ 128 } 129 } 130 } 131 return values 132 }