在Go语言中,对slice和map是我们最常用的数据结构。比如,计算两个切片的交集、差集;判断切片中的元素是否都满足某个条件的等。我推荐大家使用这个包:[elliotchance/pie](https://github.com/elliotchance/pie)
。
该包封装了对切片和map的常用操作,能满足工作中的大部分需求。比如计算切片的交集、差集;对切片中元素按条件过滤的Filter函数;对切片中元素进行数据转换的Each、Map函数等。
同时具有高性能、类型安全的特点。实现中对各函数的参数都做了类型的限制。比如Average函数就只能对整型和浮点型参数有效。
使用pie包的要求:
pie v2版本需要Go 1.18 。Go1.17及以下版本需要使用v1版本。
pie包的目标:
- 类型安全:无论是在v1版本还是v2版本的泛型中,都对类型做了限制,所以不会遇到运行时类型错误。
- 高性能:该库需要跟原生的Go实现一样快,否则该库封装就没有意义。
- Nil安全:该库的所有函数都能接收nil参数,并将其视为空切片,而不会引起panic。
- 对原切片无副作用:所有的函数对传入的切片参数都不会做修改。
使用示例
go 版本在1.18及以上,会使用pie/v2包,该包使用的是泛型。
代码语言:javascript复制package main
import (
"fmt"
"strings"
"github.com/elliotchance/pie/v2"
)
func main() {
name := pie.Of([]string{"Bob", "Sally", "John", "Jane"}).
FilterNot(func(name string) bool {
return strings.HasPrefix(name, "J")
}).
Map(strings.ToUpper).
Last()
fmt.Println(name) // "SALLY"
}
go1.17及以下版本需要使用pie/v1包。因为在1.17之前go还不支持泛型,所以函数只能针对特定类型的切片。在该v1包中,pie实际上是定义了一组类型切片。比如,代表string切片的pie.Strings类型。代表float64切片的pie.Float64s类型。那么该版本在使用时需要先定义切片的类型。如下:
代码语言:javascript复制package main
import (
"fmt"
"strings"
"github.com/elliotchance/pie/pie"
)
func main() {
var names pie.Strings //看pie的源码Strings的底层类型是[]string
names = []string{"Bob", "Sally", "John", "Jane"}
name := names.FilterNot(func(name string) bool {
return strings.HasPrefix(name, "J")
}).
Map(strings.ToUpper).
Last()
fmt.Println(name) // "SALLY"
}
pie包支持的功能:
- 切片中的元素是否全部或任意一个满足指定的条件。
- All函数:判断切片中的元素是否都满足指定的条件。
- Any函数:判断切片中的元素只要有1个满足指定条件即可。
- 对切片元素进行排序功能。
- AreSorted函数:判断切片是否是有序的
- Sort函数:对切片元素进行排序。
- SortStableUsing函数:使用指定的条件对切片进行排序,并且具有稳定性。
- SortUsing函数
- 对切片中的元素去重。
- 判断切片中的元素是否不重复的AreUnique函数、去重函数Unique
- 对切片进行前、后截取。
- Bottom函数:取切片后n个元素
- Top函数:取切片前n个元素
- DropTop函数:丢掉切片的前n个元素,并返回剩余的元素切片
- 两个或多个切片之间的集合运算
- Diff函数:计算两个切片中的差集
- Intersect函数:计算两个或多个切片的交集
- 切片元素进行算数运算功能(只针对Integer和float类型的切片有效)。
- Max函数:返回切片中的最大元素
- Min函数:返回切片中的最小元素
- Product函数:对切片所有元素进行乘积运算
- Sum函数:对切片中所有元素进行求和运算
- Average函数:求所有元素的平均值
- 对切片中的元素进行数据转换功能:Each、Map、Filter、Flat、Reducer
- 针对map的操作:
- Keys函数:获取map的所有键
- Values函数:获取map的所有值
更多、更详细的功能请参考pie包的源码。
总结
pie包几乎把slice经常用到的功能都做了封装,可谓是给开发者节省了大量时间。同时,v2包利用了泛型中的类型限制,保证了类型的安全。在性能方面,该包采用了很多策略:在已知切片长度的情况下尽可能给slice分配固定长度的内存,减少在使用append时内存申请的次数;使用切片截取的形式,避免内存再次分配。