github.com/gogf/gf/v2@v2.7.4/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  	"github.com/gogf/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  }