1 Star 1 Fork 0

lihao1988/go-array

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
文件
克隆/下载
array.go 14.52 KB
一键复制 编辑 原始数据 按行查看 历史
lgmin1988 提交于 2年前 . go array
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578
package array
import (
"errors"
"fmt"
"reflect"
"regexp"
)
var simpleTypes = []string{
"bool", "int", "int8", "int16", "int32", "int64", "uint", "uint8",
"uint16", "uint32", "uint64", "uintptr", "float32", "float64", "string",
}
// Column array column to be new array
// php array_column
func Column(dest, input interface{}, columnKey, indexKey string) {
// data validate
if columnKey == "" && indexKey == "" {
panic("columnKey or indexKey must be at least one has value")
}
// dest interface
dValue := reflect.ValueOf(dest)
if dValue.Kind() != reflect.Ptr || dValue.IsNil() {
panic(fmt.Sprintf("haystack: d type[%T] error", reflect.TypeOf(dValue)))
}
dType, dElemType, dKeyType := indirectForArr(dValue)
if !In(dKeyType, simpleTypes) {
// only support 'simpleType'
panic("haystack: dest key type must be 'simpleType'")
}
if indexKey != "" {
if dType != reflect.Map {
panic("haystack: dest type must be map")
}
} else {
if dType != reflect.Slice && dType != reflect.Array {
panic("haystack: dest type must be slice or array ")
}
}
// input interface - columnKey and indexKey
inValue := reflect.ValueOf(input)
inPrtEValue, inType := indirectSimple(inValue)
inElemKind, inKeyType, inElemType := columnElemType(inPrtEValue, inType, columnKey, indexKey)
if inElemKind == reflect.Struct && ((columnKey != "" && !isFirstLetterUp(columnKey)) ||
(indexKey != "" && !isFirstLetterUp(indexKey))) {
panic("columnKey or indexKey must be public field")
}
// no relation with pkg_path
if inKeyType != dKeyType {
panic("'dest' key type does not consist with 'input[indexKey]' type")
}
// no relation with pkg_path
if inElemType != dElemType {
panic("'dest' elem type does not consist with 'input[columnKey]' type")
}
// data operation
dValueElem := ptrToElem(dValue)
var tempKey, tempColumn reflect.Value
switch inValue.Kind() {
case reflect.Slice, reflect.Array:
for i := 0; i < inValue.Len(); i++ {
tempColumn = inValue.Index(i)
if inElemKind == reflect.Struct {
if indexKey != "" {
tempKey = tempColumn.FieldByName(indexKey)
}
if columnKey != "" {
tempColumn = tempColumn.FieldByName(columnKey)
}
} else {
if indexKey != "" {
tempKey = tempColumn.MapIndex(reflect.ValueOf(indexKey))
}
if columnKey != "" {
tempColumn = tempColumn.MapIndex(reflect.ValueOf(columnKey))
}
}
dValueElem = columnSetValue(dType, dValueElem, tempColumn, tempKey)
}
case reflect.Map:
for _, k := range inValue.MapKeys() {
tempColumn = inValue.MapIndex(k)
if inElemKind == reflect.Struct {
if indexKey != "" {
tempKey = tempColumn.FieldByName(indexKey)
}
if columnKey != "" {
tempColumn = tempColumn.FieldByName(columnKey)
}
} else {
if indexKey != "" {
tempKey = tempColumn.MapIndex(reflect.ValueOf(indexKey))
}
if columnKey != "" {
tempColumn = tempColumn.MapIndex(reflect.ValueOf(columnKey))
}
}
dValueElem = columnSetValue(dType, dValueElem, tempColumn, tempKey)
}
}
// set elem data
dValue.Elem().Set(dValueElem)
}
// columnSetValue set column elem data
func columnSetValue(rKind reflect.Kind, rv, column, key reflect.Value) reflect.Value {
switch rKind {
case reflect.Slice, reflect.Array:
rv = reflect.Append(rv, column)
case reflect.Map:
if rv.IsNil() {
panic("columnSetValue: reflect.Value is nil")
}
rv.SetMapIndex(key, column)
}
return rv
}
// columnElemType analysis column type and index type
func columnElemType(rv reflect.Value, rt reflect.Type, columnKey, indexKey string) (reflect.Kind, string, string) {
var err error
var elemKind reflect.Kind
var keyType, elemType string
switch rv.Kind() {
case reflect.Slice, reflect.Array, reflect.Map:
// indexKey operation
if indexKey == "" {
keyType = reflect.Int.String()
} else {
elemKind, keyType, err = fieldElemType(rt.Elem(), indexKey)
if err != nil {
panic(err.Error())
}
}
// columnKey operation
if columnKey == "" {
elemType = rt.Elem().String()
} else {
elemKind, elemType, err = fieldElemType(rt.Elem(), columnKey)
if err != nil {
panic(err.Error())
}
}
default:
panic("haystack: v type must be slice, array or map")
}
return elemKind, keyType, elemType
}
// fieldElemType analysis field type
func fieldElemType(elemRt reflect.Type, key string) (reflect.Kind, string, error) {
var err error
var elemType string
elemKind := elemRt.Kind()
switch elemKind {
case reflect.Struct:
field, isExist := elemRt.FieldByName(key)
if !isExist {
err = errors.New(fmt.Sprintf("input map has no column[%s]", key))
return elemKind, elemType, err
}
elemType = field.Type.String()
case reflect.Map:
elemType = elemRt.Elem().String()
default:
panic("haystack: elemRt type must be map or struct")
}
return elemKind, elemType, err
}
// set operation type
type setOps bool
const (
// set operation
instOps setOps = true
diffOps setOps = false
// constant data
uniqueOps bool = false
)
// Diff array Diff to d
// php array_diff
func Diff(d interface{}, dArr ...interface{}) {
// d interface
dValue := reflect.ValueOf(d)
if dValue.Kind() != reflect.Ptr || dValue.IsNil() {
panic(fmt.Sprintf("haystack: d type[%T] error", reflect.TypeOf(dValue)))
}
// array diff
diffValue := operateSetValue(dValue, diffOps, dArr...)
// set elem data
dValue.Elem().Set(diffValue)
}
// Intersect array Intersect to d
// php array_intersect
func Intersect(d interface{}, dArr ...interface{}) {
// d interface indirectForArr
dValue := reflect.ValueOf(d)
if dValue.Kind() != reflect.Ptr || dValue.IsNil() {
panic(fmt.Sprintf("haystack: d type[%T] error", reflect.TypeOf(dValue)))
}
// array intersect
instValue := operateSetValue(dValue, instOps, dArr...)
// set elem data
dValue.Elem().Set(instValue)
}
// operateSetValue operation set_value
func operateSetValue(dv reflect.Value, ops setOps, dArr ...interface{}) reflect.Value {
// check dValue
if dv.Kind() == reflect.Ptr {
dv = dv.Elem()
}
// operation set
var newValue reflect.Value
dType, _ := indirect(dv)
indirectStr := reflect.Indirect(dv)
for _, arr := range dArr {
// type compare
arrValue := reflect.ValueOf(arr)
if arrValue.Kind() == reflect.Ptr && arrValue.IsNil() {
continue
}
// new data
switch dType {
case reflect.Slice, reflect.Array:
newValue = reflect.MakeSlice(indirectStr.Type(), 0, dv.Len())
for i := 0; i < dv.Len(); i++ {
if inByRValue(dv.Index(i), arrValue) == bool(ops) {
newValue = reflect.Append(newValue, dv.Index(i))
}
}
case reflect.Map:
newValue = reflect.MakeMap(indirectStr.Type())
for _, k := range dv.MapKeys() {
if inByRValue(dv.MapIndex(k), arrValue) == bool(ops) {
newValue.SetMapIndex(k, dv.MapIndex(k))
}
}
}
// set elem data
dv.Set(newValue)
}
return dv
}
// In check d is in 'arr'
// php in_array
func In(d interface{}, arr interface{}) bool {
dValue := reflect.ValueOf(d)
arrValue := reflect.ValueOf(arr)
return inByRValue(dValue, arrValue)
}
// inByRValue in data by reflect value
func inByRValue(dV reflect.Value, arrV reflect.Value) bool {
dVKind, dvType := indirect(dV)
arrType, arrElemType, _ := indirectForArr(arrV)
if dvType != arrElemType {
// d does not consist with arr elem
return false
}
isExist := false
switch dVKind {
case reflect.Map, reflect.Array, reflect.Slice, reflect.Struct:
isExist = inDeepEqual(dV, arrV, arrType)
default:
isExist = inEqual(dV, arrV, arrType)
}
return isExist
}
// inEqual use array simple data equal
func inEqual(dV reflect.Value, arrV reflect.Value, arrT reflect.Kind) bool {
isExist := false
dV = ptrToElem(dV) // check ptr
arrV = ptrToElem(arrV) // check ptr
switch arrT {
case reflect.Slice, reflect.Array:
for i := 0; i < arrV.Len(); i++ {
if isExist = dV.Interface() == arrV.Index(i).Interface(); isExist {
break
}
}
case reflect.Map:
for _, k := range arrV.MapKeys() {
if isExist = dV.Interface() == arrV.MapIndex(k).Interface(); isExist {
break
}
}
default:
panic("haystack: arrV type must be slice, array or map")
}
return isExist
}
// inDeepEqual use array complex data equal
func inDeepEqual(dV reflect.Value, arrV reflect.Value, arrT reflect.Kind) bool {
isExist := false
dV = ptrToElem(dV) // check ptr
arrV = ptrToElem(arrV) // check ptr
switch arrT {
case reflect.Slice, reflect.Array:
for i := 0; i < arrV.Len(); i++ {
if isExist = reflect.DeepEqual(dV.Interface(), arrV.Index(i).Interface()); isExist {
break
}
}
case reflect.Map:
for _, k := range arrV.MapKeys() {
if isExist = reflect.DeepEqual(dV.Interface(), arrV.MapIndex(k).Interface()); isExist {
break
}
}
default:
panic("haystack: d type must be slice, array or map")
}
return isExist
}
// Merge array merge to d
// php array_merge
func Merge(d interface{}, dArr ...interface{}) {
// d interface indirectForArr
dValue := reflect.ValueOf(d)
if dValue.Kind() != reflect.Ptr || dValue.IsNil() {
panic(fmt.Sprintf("haystack: d type[%T] error", reflect.TypeOf(dValue)))
}
// array merge
dValueElem := ptrToElem(dValue)
dType, dElemType, dKeyType := indirectForArr(dValue)
for _, arr := range dArr {
// type compare
arrValue := reflect.ValueOf(arr)
if dValue.Kind() != reflect.Ptr || dValue.IsNil() {
continue
}
arrType, arrElemType, arrKeyType := indirectForArr(arrValue)
if arrType != dType {
panic("'dArr' type does not consist with 'd' type")
}
if arrElemType != dElemType {
panic("'dArr' elem type does not consist with 'd' elem type")
}
if dKeyType != arrKeyType {
panic("'dArr' key type does not consist with 'd' key type")
}
// data merge
arrValue = ptrToElem(arrValue)
switch dType {
case reflect.Slice, reflect.Array:
for i := 0; i < arrValue.Len(); i++ {
dValueElem = reflect.Append(dValueElem, arrValue.Index(i))
}
case reflect.Map:
for _, k := range arrValue.MapKeys() {
dValueElem.SetMapIndex(k, arrValue.MapIndex(k))
}
default:
panic("haystack: d type must be slice, array or map")
}
}
// set elem data
dValue.Elem().Set(dValueElem)
}
// Values get array values
// php array_values
func Values(d interface{}, values interface{}) {
// values interface indirectForArr
vValue := reflect.ValueOf(values)
if vValue.Kind() != reflect.Ptr || vValue.IsNil() {
panic(fmt.Sprintf("haystack: values type[%T] error", reflect.TypeOf(vValue)))
}
vType, vElemType, _ := indirectForArr(vValue)
if vType != reflect.Slice && vType != reflect.Array {
panic("haystack: values type must be slice or array")
}
// d interface indirectForArr
dValue := reflect.ValueOf(d)
dType, dElemType, _ := indirectForArr(dValue)
if vElemType != dElemType {
panic("'d' key type does not consist with 'keys' elem type")
}
vValueElem := ptrToElem(vValue)
switch dType {
case reflect.Slice, reflect.Array:
for i := 0; i < dValue.Len(); i++ {
vValueElem = reflect.Append(vValueElem, dValue.Index(i))
}
case reflect.Map:
for _, k := range dValue.MapKeys() {
vValueElem = reflect.Append(vValueElem, dValue.MapIndex(k))
}
default:
panic("haystack: d type must be slice, array or map")
}
// set elem data
vValue.Elem().Set(vValueElem)
}
// Keys get array keys
// php array_keys
func Keys(d interface{}, keys interface{}) {
// keys interface indirectForArr
keysValue := reflect.ValueOf(keys)
if keysValue.Kind() != reflect.Ptr || keysValue.IsNil() {
panic(fmt.Sprintf("haystack: keys type[%T] error", reflect.TypeOf(keysValue)))
}
keysType, keysElemType, _ := indirectForArr(keysValue)
if keysType != reflect.Slice && keysType != reflect.Array {
panic("haystack: keys type must be slice or array")
}
// d interface indirectForArr
dValue := reflect.ValueOf(d)
dType, _, dKeyType := indirectForArr(dValue)
if keysElemType != dKeyType {
panic("'keys' key type does not consist with 'd' elem type")
}
keysElem := ptrToElem(keysValue)
switch dType {
case reflect.Slice, reflect.Array:
for i := 0; i < dValue.Len(); i++ {
keysElem = reflect.Append(keysElem, reflect.ValueOf(i))
}
case reflect.Map:
for _, k := range dValue.MapKeys() {
keysElem = reflect.Append(keysElem, k)
}
default:
panic("haystack: d type must be slice, array or map")
}
// set elem data
keysValue.Elem().Set(keysElem)
}
// Unique array data de-duplication
// php array_unique
func Unique(d interface{}) {
// d interface indirectForArr
dv := reflect.ValueOf(d)
if dv.Kind() != reflect.Ptr || dv.IsNil() {
panic(fmt.Sprintf("haystack: d type[%T] error", reflect.TypeOf(dv)))
}
dvElem := ptrToElem(dv)
// unique operation
var newValue reflect.Value
dType, _ := indirect(dv)
indirectStr := reflect.Indirect(dv)
switch dType {
case reflect.Slice, reflect.Array:
newValue = reflect.MakeSlice(indirectStr.Type(), 0, dvElem.Len())
for i := 0; i < dvElem.Len(); i++ {
if inByRValue(dvElem.Index(i), newValue) == uniqueOps {
newValue = reflect.Append(newValue, dvElem.Index(i))
}
}
case reflect.Map:
newValue = reflect.MakeMap(indirectStr.Type())
for _, k := range dvElem.MapKeys() {
if inByRValue(dvElem.MapIndex(k), newValue) == uniqueOps {
newValue.SetMapIndex(k, dvElem.MapIndex(k))
}
}
}
// set elem data
dv.Elem().Set(newValue)
}
// indirect get interface kind and type
func indirect(rv reflect.Value) (reflect.Kind, string) {
// get reflect value and type
rvValue, rvType := indirectSimple(rv)
return rvValue.Kind(), rvType.String()
}
// indirectForArr get slice, array or map type
func indirectForArr(rv reflect.Value) (reflect.Kind, string, string) {
// get reflect value and type
rvValue, rvType := indirectSimple(rv)
vType := rvValue.Kind()
var vKeyType, vElemType string
switch vType {
case reflect.Slice, reflect.Array:
vKeyType = reflect.Int.String()
vElemType = rvType.Elem().String()
case reflect.Map:
vKeyType = rvType.Key().String()
vElemType = rvType.Elem().String()
default:
panic("haystack: v type must be slice, array or map")
}
return vType, vElemType, vKeyType
}
// indirectSimple indirect_simply
func indirectSimple(rv reflect.Value) (reflect.Value, reflect.Type) {
// check valid
if !rv.IsValid() {
panic("indirectSimple: reflect.Value is nil")
}
// get reflect value and type
var rvValue reflect.Value
var rvType reflect.Type
switch rv.Kind() {
case reflect.Ptr:
rvValue = rv.Elem()
rvType = rv.Type().Elem()
default:
rvValue = rv
rvType = rv.Type()
}
return rvValue, rvType
}
// ptrToElem Ptr to elem
func ptrToElem(v reflect.Value) reflect.Value {
if v.Kind() == reflect.Ptr {
v = v.Elem()
}
return v
}
// isFirstLetterUp the first letter is up
func isFirstLetterUp(s string) bool {
regObj, _ := regexp.Compile("^[A-Z].*")
return regObj.MatchString(s)
}
Loading...
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
Go
1
https://gitee.com/lihao1988/go-array.git
git@gitee.com:lihao1988/go-array.git
lihao1988
go-array
go-array
v1.1.0

搜索帮助