From 954b0b8dbf59c9b9d949ef1e4b38a7cb7fc27237 Mon Sep 17 00:00:00 2001 From: wangfeng Date: Fri, 3 Feb 2023 22:46:26 +0800 Subject: [PATCH 1/8] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E6=B3=A8=E9=87=8A,=20?= =?UTF-8?q?=E6=B3=A8=E6=98=8E=E5=AF=BC=E5=85=A5=E6=95=B0=E6=8D=AE=E6=97=B6?= =?UTF-8?q?=E7=9A=84=E4=BC=98=E5=85=88=E7=BA=A7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- dataframe_type.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dataframe_type.go b/dataframe_type.go index bd874d5..0098848 100644 --- a/dataframe_type.go +++ b/dataframe_type.go @@ -25,7 +25,7 @@ func findTypeByString(arr []string) (Type, error) { } hasStrings = true } - + // 类型优先级, string > bool > float > int, string 为默认类型 switch { case hasStrings: return SERIES_TYPE_STRING, nil -- Gitee From ba4a97a3b57e908fcc4161433f0d12b14f364431 Mon Sep 17 00:00:00 2001 From: wangfeng Date: Fri, 3 Feb 2023 22:46:55 +0800 Subject: [PATCH 2/8] =?UTF-8?q?=E5=AE=9E=E7=8E=B0=E4=B8=80=E4=B8=AA?= =?UTF-8?q?=E6=B3=9B=E5=9E=8B=E5=B8=A7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frame.go | 104 +++++++++++++++++++++++++++++++++++++++++++ frame_assign.go | 55 +++++++++++++++++++++++ frame_test.go | 24 ++++++++++ frame_type.go | 115 ++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 298 insertions(+) create mode 100644 frame.go create mode 100644 frame_assign.go create mode 100644 frame_test.go create mode 100644 frame_type.go diff --git a/frame.go b/frame.go new file mode 100644 index 0000000..a422e79 --- /dev/null +++ b/frame.go @@ -0,0 +1,104 @@ +package pandas + +import ( + "reflect" + "sync" +) + +type Frame[T GenericType] interface { + // Name 取得series名称 + Name() string + // ReName renames the series. + ReName(name string) + // Type returns the type of data the series holds. + // 返回series的数据类型 + Type() Type + // Len 获得行数 + Len() int + // Values 获得全部数据集 + Values() []T +} + +type GenericFrame[T GenericType] struct { + lock sync.RWMutex // 读写锁 + formatter StringFormatter // 字符串格式化工具 + name string // 帧名称 + type_ Type // values元素类型 + nilCount int // nil和nan的元素有多少, 这种统计在bool和int64类型中不会大于0, 只对float64及string有效 + rows int // 行数 + values []T // 只能是一个一维slice, 在所有的运算中, values强制转换成float64切片 +} + +func NewFrame[T GenericType](name string, values ...any) Frame[T] { + frame := GenericFrame[T]{ + formatter: DefaultFormatter, + name: name, + type_: SERIES_TYPE_INVAILD, + nilCount: 0, + rows: 0, + values: nil, + } + // 确定泛型的具体类型, 以便后面创建slice + kind := checkoutRawType(&frame) + if kind == SERIES_TYPE_INVAILD { + return &frame + } + frame.type_ = kind + if frame.type_ == SERIES_TYPE_BOOL { + // bool + frame.values = reflect.MakeSlice(typeBool, 0, 0).Interface().([]T) + } else if frame.type_ == SERIES_TYPE_INT { + // int64 + frame.values = reflect.MakeSlice(typeInt64, 0, 0).Interface().([]T) + } else if frame.type_ == SERIES_TYPE_FLOAT { + // float64 + frame.values = reflect.MakeSlice(typeFloat64, 0, 0).Interface().([]T) + } else { + // string, 字符串最后容错使用 + frame.values = reflect.MakeSlice(typeString, 0, 0).Interface().([]T) + } + size := 0 + for idx, v := range values { + vv := reflect.ValueOf(v) + vk := vv.Kind() + switch vk { + case reflect.Invalid: // {interface} nil + frame.assign(idx, size, nil) + case reflect.Slice, reflect.Array: // 切片或者数组 + for i := 0; i < vv.Len(); i++ { + tv := vv.Index(i).Interface() + frame.assign(idx, size, tv) + } + default: + // 默认为基础数据类型 + tv := vv.Interface() + frame.assign(idx, size, tv) + } + } + return &frame +} + +func (self *GenericFrame[T]) Name() string { + //TODO implement me + panic("implement me") +} + +func (self *GenericFrame[T]) ReName(name string) { + //TODO implement me + panic("implement me") +} + +func (self *GenericFrame[T]) Type() Type { + //TODO implement me + panic("implement me") +} + +func (self *GenericFrame[T]) Len() int { + //TODO implement me + panic("implement me") +} + +func (self *GenericFrame[T]) Values() []T { + //TODO implement me + panic("implement me") +} diff --git a/frame_assign.go b/frame_assign.go new file mode 100644 index 0000000..13709b2 --- /dev/null +++ b/frame_assign.go @@ -0,0 +1,55 @@ +package pandas + +import "reflect" + +// 赋值 +func (self *GenericFrame[T]) assign(idx, size int, val any) { + var v any + if self.type_ == SERIES_TYPE_BOOL { + v = AnyToBool(val) + } else if self.type_ == SERIES_TYPE_INT { + v = AnyToInt64(val) + } else if self.type_ == SERIES_TYPE_FLOAT { + v = AnyToFloat64(val) + } else { + v = AnyToString(val) + } + //// 检测类型 + //if self.type_ == SERIES_TYPE_INVAILD { + // _type, _ := detectTypes(v) + // if _type != SERIES_TYPE_INVAILD { + // self.type_ = _type + // } + //} + _vv := reflect.ValueOf(v) + _vi := _vv.Interface() + // float和string类型有可能是NaN, 对nil和NaN进行计数 + if self.type_ == SERIES_TYPE_FLOAT && Float64IsNaN(_vi.(float64)) { + self.nilCount++ + } else if self.type_ == SERIES_TYPE_STRING && StringIsNaN(_vi.(string)) { + self.nilCount++ + // 以下修正string的NaN值, 统一为"NaN" + //_rv := reflect.ValueOf(StringNaN) + //_vv.Set(_rv) // 这样赋值会崩溃 + // TODO:值可修改条件之一: 可被寻址 + // 通过反射修改变量值的前提条件之一: 这个值必须可以被寻址, 简单地说就是这个变量必须能被修改. + // 第一步: 通过变量v反射(v的地址) + _vp := reflect.ValueOf(&v) + // 第二步: 取出v地址的元素(v的值) + _vv := _vp.Elem() + // 判断_vv是否能被修改 + if _vv.CanSet() { + // 修改v的值为新值 + _vv.SetString(StringNaN) + // 执行之后, 通过debug可以看到assign入参的v已经变成了"NaN" + } + } + // 确保只添加了1个元素 + if idx < size { + self.values[idx] = v.(T) + } else { + self.values = append(self.values, v.(T)) + } + // 行数+1 + self.rows += 1 +} diff --git a/frame_test.go b/frame_test.go new file mode 100644 index 0000000..9ef7eb4 --- /dev/null +++ b/frame_test.go @@ -0,0 +1,24 @@ +package pandas + +import ( + "fmt" + "testing" +) + +func TestNewFrameT1(t *testing.T) { + f1 := []float64{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, NaN(), 12} + f2 := []float64{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12} + s1 := []string{"a", "b", "c"} + i1 := []int64{11, 12, 13, 14, 15, 16, 17, 18, 19, 20} + gf1 := NewFrame[float64]("x", f1) + fmt.Printf("%+v\n", gf1) + + t0 := []any{nil, 1, true, "abc", 3.45, NaN()} + gf2 := NewFrame[float64]("x", t0...) + fmt.Printf("%+v\n", gf2) + _ = f1 + _ = f2 + _ = s1 + _ = i1 + _ = gf1 +} diff --git a/frame_type.go b/frame_type.go new file mode 100644 index 0000000..1eff54a --- /dev/null +++ b/frame_type.go @@ -0,0 +1,115 @@ +package pandas + +import ( + "reflect" + "strings" +) + +var ( + //kindNames = []string{ + // reflect.Invalid: "invalid", + // reflect.Bool: "bool", + // reflect.Int: "int", + // reflect.Int8: "int8", + // reflect.Int16: "int16", + // reflect.Int32: "int32", + // reflect.Int64: "int64", + // reflect.Uint: "uint", + // reflect.Uint8: "uint8", + // reflect.Uint16: "uint16", + // reflect.Uint32: "uint32", + // reflect.Uint64: "uint64", + // reflect.Uintptr: "uintptr", + // reflect.Float32: "float32", + // reflect.Float64: "float64", + // reflect.Complex64: "complex64", + // reflect.Complex128: "complex128", + // reflect.Array: "array", + // reflect.Chan: "chan", + // reflect.Func: "func", + // reflect.Interface: "interface", + // reflect.Map: "map", + // reflect.Pointer: "ptr", + // reflect.Slice: "slice", + // reflect.String: "string", + // reflect.UnsafePointer: "unsafe.Pointer", + //} + + sKindInvalid = "invalid" + sKindBool = "bool" + sKindInt = "int" + sKindInt8 = "int8" + sKindInt16 = "int16" + sKindInt32 = "int32" + sKindInt64 = "int64" + sKindUint = "uint" + sKindUint8 = "uint8" + sKindUint16 = "uint16" + sKindUint32 = "uint32" + sKindUint64 = "uint64" + sKindUintptr = "uintptr" + sKindFloat32 = "float32" + sKindFloat64 = "float64" + sKindComplex64 = "complex64" + sKindComplex128 = "complex128" + sKindArray = "array" + sKindChan = "chan" + sKindFunc = "func" + sKindInterface = "interface" + sKindMap = "map" + sKindPointer = "ptr" + sKindSlice = "slice" + sKindString = "string" + sKindUnsafePointer = "unsafe.Pointer" + // 缓存Kind对应关系 + mapKind = map[string]reflect.Kind{ + sKindInvalid: reflect.Invalid, + sKindBool: reflect.Bool, + sKindInt: reflect.Int, + sKindInt8: reflect.Int8, + sKindInt16: reflect.Int16, + sKindInt32: reflect.Int32, + sKindInt64: reflect.Int64, + sKindUint: reflect.Uint, + sKindUint8: reflect.Uint8, + sKindUint16: reflect.Uint16, + sKindUint32: reflect.Uint32, + sKindUint64: reflect.Uint64, + sKindUintptr: reflect.Uintptr, + sKindFloat32: reflect.Float32, + sKindFloat64: reflect.Float64, + sKindComplex64: reflect.Complex64, + sKindComplex128: reflect.Complex128, + sKindArray: reflect.Array, + sKindChan: reflect.Chan, + sKindFunc: reflect.Func, + sKindInterface: reflect.Interface, + sKindMap: reflect.Map, + sKindPointer: reflect.Pointer, + sKindSlice: reflect.Slice, + sKindString: reflect.String, + sKindUnsafePointer: reflect.UnsafePointer, + } +) + +func checkoutRawType(frame any) Type { + ft := reflect.TypeOf(frame) + strType := ft.String() + pos := strings.LastIndexByte(strType, '[') + if pos < 0 { + return SERIES_TYPE_INVAILD + } + strType = strType[pos+1:] + pos = strings.LastIndexByte(strType, ']') + if pos < 0 { + return SERIES_TYPE_INVAILD + } + strType = strings.TrimSpace(strType[:pos]) + if len(strType) < 1 { + return SERIES_TYPE_INVAILD + } + if t, ok := mapKind[strType]; ok { + return t + } + return SERIES_TYPE_INVAILD +} -- Gitee From 6e92be57e72e4f80a33d15bc5fea6c43ddef7c7b Mon Sep 17 00:00:00 2001 From: wangfeng Date: Fri, 3 Feb 2023 22:52:38 +0800 Subject: [PATCH 3/8] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E6=B3=A8=E9=87=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- generic_range.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/generic_range.go b/generic_range.go index e6eca6b..649244f 100644 --- a/generic_range.go +++ b/generic_range.go @@ -5,6 +5,7 @@ import ( "reflect" ) +// Copy 复制一个副本 func (self *NDFrame) Copy() Series { vlen := self.Len() return self.Subset(0, vlen, true) @@ -112,7 +113,7 @@ func (self *NDFrame) oldSubset(start, end int, opt ...any) Series { return s } -// 选取一段记录 +// Select 选取一段记录 func (self *NDFrame) Select(r Range) Series { start, end, err := r.Limits(self.Len()) if err != nil { -- Gitee From a4392371b4ff77df730968a682fecc19ca531d2c Mon Sep 17 00:00:00 2001 From: wangfeng Date: Sat, 4 Feb 2023 08:56:35 +0800 Subject: [PATCH 4/8] =?UTF-8?q?=E8=BF=99=E6=AE=B5=E4=BB=A3=E7=A0=81?= =?UTF-8?q?=E6=98=AF=E5=AE=9E=E9=AA=8C,=20=E8=80=83=E8=99=91=E4=B8=80?= =?UTF-8?q?=E4=B8=AA=E9=97=AE=E9=A2=98,=20=E5=8F=8D=E5=B0=84=E5=92=8C.(typ?= =?UTF-8?q?e)=E5=93=AA=E4=B8=AA=E6=9B=B4=E5=BF=AB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- type_float32.go | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/type_float32.go b/type_float32.go index a8ac25c..f7db288 100644 --- a/type_float32.go +++ b/type_float32.go @@ -58,6 +58,14 @@ func float32ToString(v float32) string { func AnyToFloat32(v any) float32 { if isPoint(v) { + //vv := reflect.ValueOf(v) + //if vv.Kind() == reflect.Pointer { + // if vv.IsNil() { + // return Nil2Float32 + // } + // v = vv.Elem() + // vv.Float() + //} return point_to_number[float32](v, Nil2Float32, boolToFloat32, ParseFloat32) } f := value_to_number[float32](v, Nil2Float32, boolToFloat32, ParseFloat32) -- Gitee From e825095fde22ea667adeb8d73527187f1434cd9b Mon Sep 17 00:00:00 2001 From: wangfeng Date: Sat, 4 Feb 2023 10:29:35 +0800 Subject: [PATCH 5/8] =?UTF-8?q?=E5=A4=87=E6=B3=A8LoadRecords=E7=9A=84?= =?UTF-8?q?=E5=87=BD=E6=95=B0=E7=89=B9=E7=82=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- dataframe_records.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/dataframe_records.go b/dataframe_records.go index 6c14403..fd7072b 100644 --- a/dataframe_records.go +++ b/dataframe_records.go @@ -5,6 +5,7 @@ import ( ) // LoadRecords creates a new DataFrame based on the given records. +// 这个方法是从本地缓存文件读取数据的第二步, 数据从形式上只能是字符串 func LoadRecords(records [][]string, options ...LoadOption) DataFrame { // Set the default load options cfg := loadOptions{ @@ -71,10 +72,11 @@ func LoadRecords(records [][]string, options ...LoadOption) DataFrame { for i, colname := range headers { cols := rawcols[i] col := NewSeries(types[i], colname, cols) + //col := NewSeriesWithType(types[i], colname, cols) //if col.Err != nil { // return DataFrame{Err: col.Err} //} - columns[i] = *col + columns[i] = col } nrows, ncols, err := checkColumnsDimensions(columns...) if err != nil { -- Gitee From 219cdd5d156800c480a58c075c026f3b404ceec9 Mon Sep 17 00:00:00 2001 From: wangfeng Date: Sat, 4 Feb 2023 10:32:21 +0800 Subject: [PATCH 6/8] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E9=80=89=E6=8B=A9?= =?UTF-8?q?=E5=88=97=E3=80=81=E6=94=B9=E5=90=8D=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- dataframe_select.go | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 dataframe_select.go diff --git a/dataframe_select.go b/dataframe_select.go new file mode 100644 index 0000000..05a7016 --- /dev/null +++ b/dataframe_select.go @@ -0,0 +1,39 @@ +package pandas + +import "fmt" + +// Col returns a copy of the Series with the given column name contained in the DataFrame. +// 选取一列 +func (df DataFrame) Col(colname string) Series { + if df.Err != nil { + return NewSeriesWithType(SERIES_TYPE_INVAILD, "") + } + // Check that colname exist on dataframe + idx := findInStringSlice(colname, df.Names()) + if idx < 0 { + return NewSeriesWithType(SERIES_TYPE_INVAILD, "") + } + return df.columns[idx].Copy() +} + +// SetNames changes the column names of a DataFrame to the ones passed as an +// argument. +// 修改全部的列名 +func (df DataFrame) SetNames(colnames ...string) error { + if len(colnames) != df.ncols { + return fmt.Errorf("setting names: wrong dimensions") + } + for k, s := range colnames { + df.columns[k].Rename(s) + } + return nil +} + +// SetName 修改一个series的名称 +func (df DataFrame) SetName(from string, to string) { + for _, s := range df.columns { + if s.Name() == from { + s.Rename(to) + } + } +} -- Gitee From 70c48cf80412b82e6a38c19fa3ab8dbb1ee3cb17 Mon Sep 17 00:00:00 2001 From: wangfeng Date: Sat, 4 Feb 2023 10:34:43 +0800 Subject: [PATCH 7/8] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E9=80=89=E6=8B=A9?= =?UTF-8?q?=E5=88=97=E3=80=81=E6=94=B9=E5=90=8D=E7=9A=84=E6=B5=8B=E8=AF=95?= =?UTF-8?q?=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- tests/series1_test.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/series1_test.go b/tests/series1_test.go index 8c1f953..61494a5 100644 --- a/tests/series1_test.go +++ b/tests/series1_test.go @@ -29,7 +29,7 @@ Spain,2012-02-01,66,555.42,00241 _ = df.WriteCSV(buf) df = pandas.ReadCSV(filename) fmt.Println(df) - //df.SetNames("a", "b", "c", "d", "e") + df.SetNames("a", "b", "c", "d", "e") //s1 := df.Col("d") //fmt.Println(s1) // @@ -37,6 +37,8 @@ Spain,2012-02-01,66,555.42,00241 //ma5 := closes.Rolling(5).Mean() //dframe.NewSeries(closes, dframe.Float, "") //fmt.Println(ma5) + d := df.Col("d") + fmt.Println(d) _ = csvStr } -- Gitee From 59c4f0b06a78172c7d231f27c7e291c6c806eaa7 Mon Sep 17 00:00:00 2001 From: wangfeng Date: Sat, 4 Feb 2023 10:40:16 +0800 Subject: [PATCH 8/8] =?UTF-8?q?#I6CC1Z=20=E5=AE=9E=E7=8E=B0series=20?= =?UTF-8?q?=E6=B3=9B=E5=9E=8B=E6=9E=84=E9=80=A0=E6=96=B9=E6=B3=95,=20?= =?UTF-8?q?=E6=97=A9=E6=9C=9F=E6=BA=90=E8=87=AAgota=E7=9A=84seriesXXX?= =?UTF-8?q?=E5=8F=AF=E4=BB=A5=E4=B8=8D=E7=94=A8=E4=BA=86=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- generic.go | 2 +- generic_test.go | 6 ++-- series.go | 21 +++++++++++-- series_generic.go | 70 +++++++++++++++++++++++++++++++----------- series_generic_test.go | 4 +-- 5 files changed, 77 insertions(+), 26 deletions(-) diff --git a/generic.go b/generic.go index 2411e38..cc04076 100644 --- a/generic.go +++ b/generic.go @@ -12,7 +12,7 @@ type GenericType interface { ~bool | ~int64 | ~float64 | ~string } -// NDFrame 这里本意是想做一个父类 +// NDFrame 这里本意是想做一个父类, 实际的效果是一个抽象类 type NDFrame struct { lock sync.RWMutex // 读写锁 formatter StringFormatter // 字符串格式化工具 diff --git a/generic_test.go b/generic_test.go index c2bca3e..fda2edb 100644 --- a/generic_test.go +++ b/generic_test.go @@ -16,12 +16,14 @@ func TestSeriesFrame(t *testing.T) { fmt.Printf("%+v\n", s2) var s3 Series - s3 = NewSeriesBool("x", data) + // s3 = NewSeriesBool("x", data) + s3 = NewSeries(SERIES_TYPE_BOOL, "x", data) fmt.Printf("%+v\n", s3.Values()) var s4 Series ts4 := GenericSeries[float64]("x", data...) - s4 = *ts4 + ts4 = NewSeries(SERIES_TYPE_FLOAT, "x", data) + s4 = ts4 fmt.Printf("%+v\n", s4.Values()) } diff --git a/series.go b/series.go index 1a52493..2cb8507 100644 --- a/series.go +++ b/series.go @@ -74,7 +74,22 @@ type Series interface { } // NewSeries 指定类型创建序列 -func NewSeries(t Type, name string, vals ...interface{}) *Series { +func NewSeries(t Type, name string, vals any) Series { + var series Series + if t == SERIES_TYPE_BOOL { + series = NewSeriesWithType(SERIES_TYPE_BOOL, name, vals) + } else if t == SERIES_TYPE_INT { + series = NewSeriesWithType(SERIES_TYPE_INT, name, vals) + } else if t == SERIES_TYPE_STRING { + series = NewSeriesWithType(SERIES_TYPE_STRING, name, vals) + } else { + // 默认全部强制转换成float64 + series = NewSeriesWithType(SERIES_TYPE_FLOAT, name, vals) + } + return series +} + +func NewSeries_old(t Type, name string, vals ...interface{}) *Series { var series Series if t == SERIES_TYPE_BOOL { series = NewSeriesBool(name, vals...) @@ -89,8 +104,8 @@ func NewSeries(t Type, name string, vals ...interface{}) *Series { return &series } -// 泛型方法, 构造序列, 比其它方式对类型的统一性要求更严格 -func GenericSeries[T GenericType](name string, values ...T) *Series { +// GenericSeries 泛型方法, 构造序列, 比其它方式对类型的统一性要求更严格 +func GenericSeries[T GenericType](name string, values ...T) Series { // 第一遍, 确定类型, 找到第一个非nil的值 var _type Type = SERIES_TYPE_STRING for _, v := range values { diff --git a/series_generic.go b/series_generic.go index d07cec3..a95d79d 100644 --- a/series_generic.go +++ b/series_generic.go @@ -31,7 +31,17 @@ func CreateSeries(t Type, name string, v ...any) Series { return &frame } -func NewSeries2(name string, values ...interface{}) Series { +// NewSeriesWithoutType 不带类型创新一个新series +func NewSeriesWithoutType(name string, values ...interface{}) Series { + _type, err := detectTypeBySlice(values) + if err != nil { + return nil + } + return NewSeriesWithType(_type, name, values...) +} + +// NewSeriesWithType 通过类型创新一个新series +func NewSeriesWithType(_type Type, name string, values ...interface{}) Series { frame := NDFrame{ formatter: DefaultFormatter, name: name, @@ -40,11 +50,10 @@ func NewSeries2(name string, values ...interface{}) Series { rows: 0, //values: []E{}, } - _type, err := detectTypeBySlice(values) - //fmt.Println(_type, err) - if err != nil { - return nil - } + //_type, err := detectTypeBySlice(values) + //if err != nil { + // return nil + //} frame.type_ = _type if frame.type_ == SERIES_TYPE_BOOL { // bool @@ -63,20 +72,45 @@ func NewSeries2(name string, values ...interface{}) Series { //size := len(series.values) size := 0 for idx, v := range values { - if frame.type_ == SERIES_TYPE_BOOL { - val := AnyToBool(v) - assign[bool](&frame, idx, size, val) - } else if frame.type_ == SERIES_TYPE_INT { - val := AnyToInt64(v) - assign[int64](&frame, idx, size, val) - } else if frame.type_ == SERIES_TYPE_FLOAT { - val := AnyToFloat64(v) - assign[float64](&frame, idx, size, val) - } else { - val := AnyToString(v) - assign[string](&frame, idx, size, val) + switch val := v.(type) { + case nil, int8, uint8, int16, uint16, int32, uint32, int64, uint64, int, uint, float32, float64, bool, string: + // 基础类型 + series_append(&frame, idx, size, val) + default: + vv := reflect.ValueOf(val) + vk := vv.Kind() + switch vk { + //case reflect.Invalid: // {interface} nil + // series.assign(idx, size, Nil2Float64) + case reflect.Slice, reflect.Array: // 切片或数组 + for i := 0; i < vv.Len(); i++ { + tv := vv.Index(i).Interface() + //series.assign(idx, size, str) + series_append(&frame, idx, size, tv) + } + case reflect.Struct: // 忽略结构体 + continue + default: + series_append(&frame, idx, size, nil) + } } } return &frame } + +func series_append(frame *NDFrame, idx, size int, v any) { + if frame.type_ == SERIES_TYPE_BOOL { + val := AnyToBool(v) + assign[bool](frame, idx, size, val) + } else if frame.type_ == SERIES_TYPE_INT { + val := AnyToInt64(v) + assign[int64](frame, idx, size, val) + } else if frame.type_ == SERIES_TYPE_FLOAT { + val := AnyToFloat64(v) + assign[float64](frame, idx, size, val) + } else { + val := AnyToString(v) + assign[string](frame, idx, size, val) + } +} diff --git a/series_generic_test.go b/series_generic_test.go index 82c1bf6..c034e6e 100644 --- a/series_generic_test.go +++ b/series_generic_test.go @@ -7,10 +7,10 @@ import ( func TestCreateSeries(t *testing.T) { t0 := []any{1, true, "abc", 3.45, NaN()} - df0 := NewSeries2("x", t0...) + df0 := NewSeriesWithoutType("x", t0...) fmt.Printf("%+v\n", df0) - s1 := NewSeries2("sales", nil, 50.3, 23.4, 56.2) + s1 := NewSeriesWithoutType("sales", nil, 50.3, 23.4, 56.2) fmt.Println(s1) var values any -- Gitee