diff --git a/.CHANGELOG.md b/.CHANGELOG.md index 3d48ca40..14a849a6 100644 --- a/.CHANGELOG.md +++ b/.CHANGELOG.md @@ -12,6 +12,7 @@ - [mapx: LinkedMap 特性](https://github.com/ecodeclub/ekit/pull/191) - [copier: ReflectCopier 支持忽略字段](https://github.com/ecodeclub/ekit/pull/196) - [syncx: 重构LoadOrStoreFunc方法及相关测试](https://github.com/ecodeclub/ekit/pull/198) +- [slice: 添加Add函数,在指定位置插入元素](https://github.com/ecodeclub/ekit/pull/201) # v0.0.7 - [slice: FilterDelete](https://github.com/ecodeclub/ekit/pull/152) diff --git a/internal/slice/add.go b/internal/slice/add.go new file mode 100644 index 00000000..c368c50c --- /dev/null +++ b/internal/slice/add.go @@ -0,0 +1,35 @@ +// Copyright 2021 ecodeclub +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package slice + +import "github.com/ecodeclub/ekit/internal/errs" + +func Add[T any](src []T, element T, index int) ([]T, error) { + length := len(src) + if index < 0 || index >= length { + return nil, errs.NewErrIndexOutOfRange(length, index) + } + + //先将src扩展一个元素 + var zeroValue T + src = append(src, zeroValue) + for i := len(src) - 1; i > index; i-- { + if i-1 >= 0 { + src[i] = src[i-1] + } + } + src[index] = element + return src, nil +} diff --git a/internal/slice/add_test.go b/internal/slice/add_test.go new file mode 100644 index 00000000..7236aece --- /dev/null +++ b/internal/slice/add_test.go @@ -0,0 +1,78 @@ +// Copyright 2021 ecodeclub +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package slice + +import ( + "testing" + + "github.com/ecodeclub/ekit/internal/errs" + "github.com/stretchr/testify/assert" +) + +func TestAdd(t *testing.T) { + testCases := []struct { + name string + slice []int + addVal int + index int + wantSlice []int + wantErr error + }{ + { + name: "index 0", + slice: []int{123, 100}, + addVal: 233, + index: 0, + wantSlice: []int{233, 123, 100}, + }, + { + name: "index middle", + slice: []int{123, 124, 125}, + addVal: 233, + index: 1, + wantSlice: []int{123, 233, 124, 125}, + }, + { + name: "index out of range", + slice: []int{123, 100}, + index: 12, + wantErr: errs.NewErrIndexOutOfRange(2, 12), + }, + { + name: "index less than 0", + slice: []int{123, 100}, + index: -1, + wantErr: errs.NewErrIndexOutOfRange(2, -1), + }, + { + name: "index last", + slice: []int{123, 100, 101, 102, 102, 102}, + addVal: 233, + index: 5, + wantSlice: []int{123, 100, 101, 102, 102, 233, 102}, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + res, err := Add(tc.slice, tc.addVal, tc.index) + assert.Equal(t, tc.wantErr, err) + if err != nil { + return + } + assert.Equal(t, tc.wantSlice, res) + }) + } +} diff --git a/slice/add.go b/slice/add.go new file mode 100644 index 00000000..a553a9f4 --- /dev/null +++ b/slice/add.go @@ -0,0 +1,24 @@ +// Copyright 2021 ecodeclub +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package slice + +import "github.com/ecodeclub/ekit/internal/slice" + +// Add 在index处添加元素 +// index 范围应为[0, len(src)) +func Add[Src any](src []Src, element Src, index int) ([]Src, error) { + res, err := slice.Add[Src](src, element, index) + return res, err +} diff --git a/slice/add_test.go b/slice/add_test.go new file mode 100644 index 00000000..014a9df3 --- /dev/null +++ b/slice/add_test.go @@ -0,0 +1,71 @@ +// Copyright 2021 ecodeclub +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package slice + +import ( + "fmt" + "testing" + + "github.com/ecodeclub/ekit/internal/errs" + + "github.com/stretchr/testify/assert" +) + +func TestAdd(t *testing.T) { + // Delete 主要依赖于 internal/slice.Delete 来保证正确性 + testCases := []struct { + name string + slice []int + addVal int + index int + wantSlice []int + wantErr error + }{ + { + name: "index 0", + slice: []int{123, 100}, + addVal: 233, + index: 0, + wantSlice: []int{233, 123, 100}, + }, + { + name: "index -1", + slice: []int{123, 100}, + index: -1, + wantErr: errs.NewErrIndexOutOfRange(2, -1), + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + res, err := Add(tc.slice, tc.addVal, tc.index) + assert.Equal(t, tc.wantErr, err) + if err != nil { + return + } + assert.Equal(t, tc.wantSlice, res) + }) + } +} + +func ExampleAdd() { + res, _ := Add[int]([]int{1, 2, 3, 4}, 233, 2) + fmt.Println(res) + _, err := Add[int]([]int{1, 2, 3, 4}, 233, -1) + fmt.Println(err) + // Output: + // [1 2 233 3 4] + // ekit: 下标超出范围,长度 4, 下标 -1 +}