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  }