注:以下所有的方法来自于 https://github.com/ahmetb/go-linq,只对对应方法进行用法分析.
具体的使用示例可以参考 https://godoc.org/github.com/ahmetb/go-linq#
目录
type Book struct {
Name string
Author string
Money float64
WordsNum int
PublishTime time.Time
}
type Person struct {
Name string //拥有者的名字
}
type Pet struct {
Name string //动物的名字
OwnerName string //拥有者的名字
}
type Man struct {
Name string //拥有者的名字
Pets []Pets //宠物们
}
type Pets struct {
Name string //动物的名字
}
func MakeInnerData() []Man {
man := make([]Man, 0)
man = append(man, Man{
Name: "康康",
Pets: []Pets{{Name: "康康的狗"}, {Name: "康康的猫"}},
})
man = append(man, Man{
Name: "老施",
Pets: []Pets{{Name: "老施的"}, {Name: "老施的鸟"}},
})
man = append(man, Man{
Name: "小明",
Pets: []Pets{{Name: "小明的"}, {Name: "小明的狗"}},
})
return man
}
func MakeJoinData() ([]Person, []Pet) {
kangkang := Person{Name: "爱吃合合乐的康康"}
laoshi := Person{Name: "老施"}
xiaoming := Person{Name: "不要催-小明"}
expect := Person{Name: "我是没有宠物的人"}
dog := Pet{Name: "康康的狗", OwnerName: kangkang.Name}
cat := Pet{Name: "康康的猫", OwnerName: kangkang.Name}
fish := Pet{Name: "老施的", OwnerName: laoshi.Name}
pig := Pet{Name: "小明的", OwnerName: xiaoming.Name}
return []Person{kangkang, laoshi, xiaoming, expect}, []Pet{dog, cat, fish, pig}
}
func MakeBook() []Book {
bookList := make([]Book, 0)
bookList = append(bookList, Book{
Name: "Go语言",
Author: "Go",
Money: 100,
WordsNum: 1000,
PublishTime: time.Date(2020, 1, 1, 10, 0, 0, 0, time.Local),
})
bookList = append(bookList, Book{
Name: "Effective Java",
Author: "Java",
Money: 78,
WordsNum: 9000,
PublishTime: time.Date(2020, 2, 15, 10, 0, 0, 0, time.Local),
})
bookList = append(bookList, Book{
Name: "Java语言",
Author: "Java",
Money: 50,
WordsNum: 3000,
PublishTime: time.Date(2020, 2, 1, 10, 0, 0, 0, time.Local),
})
bookList = append(bookList, Book{
Name: "Lua语言",
Author: "Lua",
Money: 75,
WordsNum: 45000,
PublishTime: time.Date(2020, 1, 10, 10, 0, 0, 0, time.Local),
})
bookList = append(bookList, Book{
Name: "React语言",
Author: "React",
Money: 99,
WordsNum: 14500,
PublishTime: time.Date(2020, 7, 1, 10, 0, 0, 0, time.Local),
})
bookList = append(bookList, Book{
Name: "Red语言",
Author: "Red",
Money: 28,
WordsNum: 880,
PublishTime: time.Date(2019, 4, 1, 10, 0, 0, 0, time.Local),
})
bookList = append(bookList, Book{
Name: "JavaScript语言",
Author: "JavaScript",
Money: 81,
WordsNum: 3776,
PublishTime: time.Date(2019, 5, 17, 10, 0, 0, 0, time.Local),
})
return bookList
}
func MakeBook1() []Book {
bookList := make([]Book, 0)
bookList = append(bookList, Book{
Name: "Go语言",
Author: "Go",
Money: 100,
WordsNum: 1000,
PublishTime: time.Date(2020, 1, 1, 10, 0, 0, 0, time.Local),
})
bookList = append(bookList, Book{
Name: "Effective Java",
Author: "Java",
Money: 78,
WordsNum: 9000,
PublishTime: time.Date(2020, 2, 15, 10, 0, 0, 0, time.Local),
})
bookList = append(bookList, Book{
Name: "Go语言(第二版)",
Author: "Go",
Money: 50,
WordsNum: 3000,
PublishTime: time.Date(2020, 2, 1, 10, 0, 0, 0, time.Local),
})
return bookList
}
func MakeBook2() []Book {
bookList := make([]Book, 0)
bookList = append(bookList, Book{
Name: "Go语言",
Author: "Go",
Money: 100,
WordsNum: 1000,
PublishTime: time.Date(2020, 1, 1, 10, 0, 0, 0, time.Local),
})
return bookList
}
func MakeBook3() []Book {
bookList := make([]Book, 0)
bookList = append(bookList, Book{
Name: "Go语言",
Author: "Go",
Money: 100,
WordsNum: 1000,
PublishTime: time.Date(2020, 1, 1, 10, 0, 0, 0, time.Local),
})
bookList = append(bookList, Book{
Name: "Go语言(第三版)",
Author: "Go",
Money: 50,
WordsNum: 3000,
PublishTime: time.Date(2020, 2, 1, 10, 0, 0, 0, time.Local),
})
return bookList
}
自定义聚合方法,提供了两个变式,一个是支持固定类型的 AggregateT 方法,一个是支持interface的 Aggregate 方法。
Aggregate提供了一个方法,支持前后两个参数:
func (q Query) Aggregate(f func(interface{}, interface{}) interface{}) interface{}
该方法就是聚合操作的具体方法,这边的使用例子如下:
func Aggregate() {
bookList := MakeBook()
query := linq.From(bookList)
// 这边的聚合操作其实就是【自定义对应的比较方法】。
// 根据注释,第一次拿到的是数组的第一个元素,然后跟第二个元素进行比较,如果第二个元素符合条件则【替换第一个元素】,否则当前聚合操作还是持有第一个元素。
// 以此类推后面的元素
result := query.Aggregate(AggregateFunc).(Book)
fmt.Println(fmt.Sprintf("聚合操作查询出的结果是【%s】这本书,它的发布时间最早为:%v", result.Name, timed.GetTimeDefaultFormatString(result.PublishTime.Unix())))
}
//自定义聚合操作方法
var AggregateFunc = func(first interface{}, second interface{}) interface{} {
if first.(Book).PublishTime.Before(second.(Book).PublishTime) {
return first
}
return second
}
AggregateT 方法支持一个自定义类型的入参,如下:
// AggregateT is the typed version of Aggregate.
//
// - f is of type: func(TSource, TSource) TSource
//
// NOTE: Aggregate has better performance than AggregateT.
func (q Query) AggregateT(f interface{}) interface{}
类似的除了方法自定义之外,这边也是支持两个入参,具体使用例子类似上面
All提供两个方法
一个是支持具体类型的 AllT 方法,
一个是支持interface的All方法,入参是一个predicate的条件方法,即返回是否所有元素都满足条件的结果,true或者false
// All determines whether all elements of a collection satisfy a condition.
func (q Query) All(predicate func(interface{}) bool) bool
这边的使用例子是:
func All() {
bookList := MakeBook()
query := linq.From(bookList)
result := query.All(PublishTimeBeforeFunc)
fmt.Println(fmt.Sprintf("是否所有的书的发表时间都早于2020年1月1号,答案是%v", result))
result = query.All(PublishTimeAfterFunc)
fmt.Println(fmt.Sprintf("是否所有的书的发表时间都晚于2018年1月1号,答案是%v", result))
}
这边提供了三个方法,Any、AnyWith、AnyWithT
Any方法返回元素是否存在的结果(true、false)
AnyWith和AnyWithT,根据传入的判断条件,返回满足判断条件的元素是否大于等于1的结果(true、false)
具体的使用例子如下:
func AnyWith() {
bookList := MakeBook()
query := linq.From(bookList)
result := query.AnyWith(PublishTimeBeforeFunc) //判断是否有任意个元素满足条件
fmt.Println(fmt.Sprintf("是否有任意书的发表时间早于2020年1月1号,答案是%v", result))
result = query.AnyWith(PublishTimeAfterFunc2) //判断是否有任意个元素满足条件
fmt.Println(fmt.Sprintf("是否有任意书的发表时间晚于2021年1月1号,答案是%v", result))
}
Where方法是通过条件判断,查询到所有满足条件的元素。这边也是提供了Where和WhereT两个方法,具体的使用例子如下:
func Where() {
bookList := MakeBook()
query := linq.From(bookList)
fmt.Println()
fmt.Println()
query.WhereT(func(book Book) bool {
return book.Money > float64(70)
}).ForEachT(func(book Book) {
fmt.Println(fmt.Sprintf("作者%v,写了一本书叫做%v", book.Author, book.Name))
})
}
计算类型的函数,这边主要介绍的是 Average:求平均值 、 Max:求最大值、 Min:求最小值,传入的类型必须是 number类型的,否则会报错,因为具体的处理也是通过switch操作.无法处理非number的类型,具体的使用例子如下:
func Calculate() {
query := linq.From([]int{1, 2, 3, 4, 5, 6, 7, 8, 9})
fmt.Println(fmt.Sprintf("平均值为:%f", query.Average()))
fmt.Println(fmt.Sprintf("最大的值为%d", query.Max()))
fmt.Println(fmt.Sprintf("最小的值为%d", query.Min()))
}
组合两个数组这边提供两个方法:
Concat:会排除掉两个Query中重复的元素
Union: 不会排除两个Query中重复的元素,有多少个元素就组合成多少个元素的Query
添加元素这边也提供了两个方法:
Append: 将新的元素添加到Query的最后一个位置
PrePend:将新的元素添加到Query的第一个位置
具体的使用例子是:
func Combine() {
bookList := MakeBook()
query := linq.From(bookList)
query1 := query.Concat(query) //不会排除重复项
query2 := query.Union(query) //会排除重复项
fmt.Println(fmt.Sprintf("不会排除重复项的方法返回的元素个数是%d", len(query1.Results())))
fmt.Println(fmt.Sprintf("会排除重复项的方法返回的元素个数是%d", len(query2.Results())))
query1 = query1.Append(Book{Name: "Last One"}) //加在原来的Query的最后面
query2 = query2.Prepend(Book{Name: "First One"}) //加在原来的Query的第一个
fmt.Println(fmt.Sprintf("最后一个元素是%v", query1.Last()))
fmt.Println(fmt.Sprintf("第一个元素是%v", query2.First()))
}
需要注意的是,query在调用了对应的方法之后,必须赋值给新的query(用等号),这样才能得到对应的结果.
需要注意的是Go在判断元素equals的操作,这边需要放到Query中的应该是结构体数组,而不是指针数组,如果是指针数组则判断的是指针地址。如果是结构体数组,则根据Go的判断,所有元素值相等则该结构体相等
Contains的具体使用方法如下:
func Contains() {
bookList := MakeBook()
query := linq.From(bookList)
//这边需要注意是的是如果要判断两个元素是否相等,在go里面不能使用元素的地址
// 所以这边加到query里面的必须不能是元素的地址,否则没办法比较结构体本身,而是比较结构体的地址
fmt.Println(fmt.Sprintf("判断当前数组是否包含相同的元素,判断的是所有的值,而不是地址,结果是%v", query.Contains(Book{
Name: "Go语言",
Author: "Go",
Money: 100,
WordsNum: 1000,
PublishTime: time.Date(2020, 1, 1, 10, 0, 0, 0, time.Local),
})))
}
First和Last分别提供了三个方法:
First返回Query中数组的第一个元素
FirstWith、FirstWithT:返回满足条件的Query数组的第一个元素
Last返回Query中数组的最后一个元素
LastWith、LastWithT:返回满足条件的Query数组的最后一个元素
具体的使用例子如下:
func FirstAndLast() {
bookList := MakeBook()
query := linq.From(bookList)
fmt.Println(fmt.Sprintf("数组第一本书书名叫:%s", query.First().(Book).Name))
fmt.Println(fmt.Sprintf("数组第一本书发布时间在2020年1月1号之前的书书名叫:%s", query.FirstWith(PublishTimeBeforeFunc).(Book).Name))
fmt.Println(fmt.Sprintf("数组最后一本书书名叫:%s", query.Last().(Book).Name))
fmt.Println(fmt.Sprintf("数组最后一本书发布时间在2020年1月1号之前的书书名叫:%s", query.LastWith(PublishTimeBeforeFunc).(Book).Name))
}
Distinct提供了三个方法
Distinct:判断结构体是否相等,返回所有唯一的结构体
DistinctBy、DistinctByT:根据对应的字段来判断是否相等,返回唯一的结构体.
使用例子如下:
func Distinct() {
bookList := MakeBook()
query := linq.From(bookList)
query = query.Append(Book{
Name: "Go语言",
Author: "Go",
Money: 100,
WordsNum: 1000,
PublishTime: time.Date(2020, 1, 1, 10, 0, 0, 0, time.Local),
})
bookList1 := make([]Book, 0)
query.ToSlice(&bookList1)
fmt.Println(fmt.Sprintf("筛选之前query中总共有%d个数据", query.Count()))
//这边的distinct如果是结构体,则判断的是结构体的所有值,如果是指针则判断的是指针地址.
query = query.Distinct()
fmt.Println(fmt.Sprintf("筛选之后query中总共有%d个数据", query.Count()))
fmt.Println()
fmt.Println("输出对应书名和作者")
query = query.Append(Book{
Name: "Go语言(第二版)",
Author: "Go",
Money: 100,
WordsNum: 1000,
PublishTime: time.Date(2020, 1, 1, 10, 0, 0, 0, time.Local),
})
//根据对应的规则来判断是否相同 -- 如果对应的字段一样,只会保留第一个找到的,后面的会被清除掉
query.DistinctByT(func(book Book) string {
return book.Author
}).ForEachT(func(book Book) {
fmt.Println(fmt.Sprintf("书名%v,作者%v", book.Name, book.Author))
})
}
Except提供两个方法:
Except: 根据结构体筛选两个Query之间的差集
ExceptBy:根据结构体的字段筛选两个Query之间的差集
实际这边是求得Query1中有但是Query2中没有的元素,具体的使用例子如下:
func Except() {
bookList1 := MakeBook1()
query1 := linq.From(bookList1)
bookList2 := MakeBook2()
query2 := linq.From(bookList2)
fmt.Println("输出对应书名和作者")
//判断结构结构体本身是否相等
query1.Except(query2).
ForEachT(func(book Book) {
fmt.Println(fmt.Sprintf("书名%v,作者%v", book.Name, book.Author))
})
fmt.Println()
fmt.Println("输出对应书名和作者")
//判断结构体的某个字段是否出现
query1.ExceptByT(query2, func(book Book) string {
return book.Author
}).ForEachT(func(book Book) {
fmt.Println(fmt.Sprintf("书名%v,作者%v", book.Name, book.Author))
})
}
GroupBy提供两个方法,提供自定义结构体的GroupByT方法和GroupBy方法。
两个方法直接指定分组对应的key和Group.对于分组的元素,可以通过结构体的一个字段作为它的key,分组结果可以是结构体也可以是某个字段或者规则
具体的使用例子如下:
func GroupBy() {
bookList1 := MakeBook1()
query := linq.From(bookList1)
fmt.Println("输出对应书名和作者")
//第一个func是分组的依据,第二个func是分组后返回的元素.
query = query.GroupByT(func(book Book) string {
return book.Author
}, func(book Book) Book {
return book
})
query.ForEachT(func(bookGroup linq.Group) {
fmt.Println(fmt.Sprintf("作者是%v", bookGroup.Key))
for _, item := range bookGroup.Group {
fmt.Println(fmt.Sprintf("书名%v,作者%v", item.(Book).Name, item.(Book).Author))
fmt.Println()
}
})
fmt.Println()
fmt.Println("输出对应书名")
bookList1 = MakeBook1()
query = linq.From(bookList1)
var nameGroups []linq.Group
query.GroupByT(
func(book Book) string { return book.Author },
func(book Book) string { return book.Name },
).ToSlice(&nameGroups)
for _, item := range nameGroups {
fmt.Println(fmt.Sprintf("作者是%v", item.Key))
for _, row := range item.Group {
fmt.Println(fmt.Sprintf("书名%v", row))
}
}
}
Intersect提供了三个方法
Intersect:根据结构体判断进行求交集
IntersectBy、IntersectByT:根据结构体字段或者规则来判断交集
具体使用例子如下:
func Intersect() {
bookList1 := MakeBook1()
query1 := linq.From(bookList1)
bookList2 := MakeBook2()
query2 := linq.From(bookList2)
fmt.Println("输出对应的书籍元素,按照结构体判断交集")
query3 := query1.Intersect(query2)
query3.ForEachT(func(book Book) {
fmt.Println(fmt.Sprintf("书名%v,作者%v", book.Name, book.Author))
})
fmt.Println()
fmt.Println("输出对应的书籍元素,按照元素判断交集")
query3 = query1.IntersectByT(query2, func(book Book) string {
return book.Author
})
query3.ForEachT(func(book Book) {
fmt.Println(fmt.Sprintf("书名%v,作者%v", book.Name, book.Author))
})
//这边计算是按照结构体的一个元素进行比较。事实证明无论是否按照结构体的元素筛选,返回的都是完全相同的元素
fmt.Println()
fmt.Println("输出对应的书籍元素,按照元素判断交集2")
bookList1 = MakeBook1()
query1 = linq.From(bookList1)
bookList3 := MakeBook3()
query2 = linq.From(bookList3)
query3 = query2.IntersectByT(query1, func(book Book) string {
return book.Author
})
query3.ForEachT(func(book Book) {
fmt.Println(fmt.Sprintf("书名%v,作者%v", book.Name, book.Author))
})
fmt.Println()
fmt.Println("判断是否会不重复的处理")
query1 = linq.From([]int{1, 2, 3, 4, 5, 3})
query2 = linq.From([]int{1, 3, 3, 78, 99, 0, 111})
query3 = query2.IntersectByT(query1, func(i int) int {
return i
})
fmt.Println(query3.Results())
}
linq提供了多个排序方法,这边包括了二次排序的方法.
按照从小到大的顺序排: Orderby 、OrderByT
按照从大到小的顺序排:OrderByDescending、OrderByDescendingT
在上一次的排序基础上按照从小到大的顺序排:ThenBy、ThenByT
在上一次的排序基础上按照从大到小的顺序排:ThenByDescending、ThenByDescendingT
具体的使用例子如下:
//OrderBy可以按照对应的规则进行排序,可以实现多重排序,需要注意的就是OrderBy是从到达,orderByDescending是从大到小
func OrderBy() {
bookList := MakeBook()
query := linq.From(bookList)
query = query.OrderByDescendingT(func(book Book) string {
return book.Name
}).ThenByDescendingT(func(book Book) string {
return book.Author
}).ThenByDescendingT(func(book Book) float64 {
return book.Money
}).Query
query.ForEachT(func(book Book) {
fmt.Println(fmt.Sprintf("书名%v,作者%v", book.Name, book.Author))
})
fmt.Println()
fmt.Println()
//reverse: 把结果逆序
query.Reverse().ForEachT(func(book Book) {
fmt.Println(fmt.Sprintf("书名%v,作者%v", book.Name, book.Author))
})
}
Skip这边提供了三个方法:
Skip(num):略过多少个元素,取剩下的元素
SkipWhile(predicate)、SkipWhileT(predicate):忽略满足条件的对应数组元素,取剩下的元素
具体的使用例子如下:
func Skip() {
bookList := MakeBook()
query := linq.From(bookList)
fmt.Println(fmt.Sprintf("跳过三个元素,返回的数组中包含%d个元素", len(query.Skip(3).Results())))
fmt.Println(fmt.Sprintf("跳过发布时间在2018.1.1之后的元素,返回的数组中包含%d个元素", query.SkipWhile(PublishTimeAfterFunc).Count()))
}
Count提供了三个方法:
Count:计算当前Query携带的数组长度
CountWith、CountWithT:计算满足条件的当前Query携带的数组长度
具体的使用例子如下:
func Count() {
bookList := MakeBook()
query := linq.From(bookList)
fmt.Println(fmt.Sprintf("数组中发布时间早于2019-1-1的书有%d本", query.CountWithT(PublishTimeBeforeFunc)))
fmt.Println(fmt.Sprintf("数组中发布时间晚于2018-1-1的书有%d本", query.CountWithT(PublishTimeAfterFunc)))
}
ToMap提供了三个方法
ToMap: 需要配合 SelectT 方法去生成返回一个 linq.KeyValue的结构,指定对应的Map的key和value
ToMapBy、ToMapByT:提供两个方法,一个方法指定key,一个方法指定value
如果key相同的话,前面的元素会被覆盖掉,ToMap方法的使用需要配合Select方法.
具体的使用例子如下:
func ToMap() {
bookList := MakeBook()
query := linq.From(bookList)
bookMap := make(map[string]string, 0)
query.SelectT(func(book Book) linq.KeyValue {
return linq.KeyValue{
Key: book.Author,
Value: book.Name,
}
}).ToMap(&bookMap)
for key, value := range bookMap {
fmt.Println(fmt.Sprintf("作者%v,写了一本书叫做%v", key, value))
}
fmt.Println()
fmt.Println()
//如果key相同的话,前面的元素会被覆盖掉(只会保留最后一个)
bookList1 := MakeBook1()
query1 := linq.From(bookList1)
bookMap1 := make(map[string]string, 0)
query1.SelectT(func(book Book) linq.KeyValue {
return linq.KeyValue{
Key: book.Author,
Value: book.Name,
}
}).ToMap(&bookMap1)
for key, value := range bookMap1 {
fmt.Println(fmt.Sprintf("作者%v,写了一本书叫做%v", key, value))
}
fmt.Println()
fmt.Println()
bookList2 := MakeBook()
query2 := linq.From(bookList2)
bookMap2 := make(map[string]Book, 0)
query2.ToMapByT(&bookMap2,
//这个方法决定key的字段是什么
func(book Book) string {
return book.Author
}, //这个方法决定value的字段是什么
func(book Book) Book {
return book
})
for key, value := range bookMap2 {
fmt.Println(fmt.Sprintf("作者%v,写了一本书叫做%v", key, value.Name))
}
}
ToSlice提供了转换数组的方法,具体例子如下:
func ToSlice(){
fmt.Println()
fmt.Println()
bookListResult := make([]Book,0)
linq.From(MakeBook()).OrderByDescendingT(func(book Book) string {
return book.Author
}).ToSlice(&bookListResult)
for _, value := range bookListResult {
fmt.Println(fmt.Sprintf("作者%v,写了一本书叫做%v", value.Author, value.Name))
}
}
Take方法提供了三个方法:
Take(num):提取对应数量的元素
TakeWhile、TakeWhileT(predicate):提取满足条件的元素,一旦某一个元素不满足条件,直接返回,不会再判断后面的元素
TakeWhile一旦遇到不满足条件的元素直接返回,不会再往下查找,一定要注意这个,不然在使用的时候很可能犯错.
具体的使用例子如下:
func Take() {
bookList := MakeBook()
query := linq.From(bookList)
query.OrderByDescendingT(func(book Book) string {
return book.Author
}).Take(3).ForEachT(func(book Book) {
fmt.Println(fmt.Sprintf("作者%v,写了一本书叫做%v", book.Author, book.Name))
})
fmt.Println()
fmt.Println()
//超出对应数量的元素会不会报错(输出所有的元素)
query.OrderByDescendingT(func(book Book) string {
return book.Author
}).Take(100).ForEachT(func(book Book) {
fmt.Println(fmt.Sprintf("作者%v,写了一本书叫做%v", book.Author, book.Name))
})
fmt.Println()
fmt.Println()
//负数会发生什么情况(直接返回,不做操作)
query.OrderByDescendingT(func(book Book) string {
return book.Author
}).Take(-2).ForEachT(func(book Book) {
fmt.Println(fmt.Sprintf("作者%v,写了一本书叫做%v", book.Author, book.Name))
})
//TakeWhile系列的方法,虽然能够根据条件进行查询,但是有一个弊端就是一旦查询到的结果和条件不符合则直接返回,也就是说后面满足条件的元素不会再被做筛选
//那么比如这边的这个大于的操作,就需要对整个数组进行排序之后然后进行筛选,如果不希望排序,则用原生的for循环可能会更好
fmt.Println()
fmt.Println()
query.TakeWhileT(func(book Book) bool {
return book.Money > float64(70)
}).ForEachT(func(book Book) {
fmt.Println(fmt.Sprintf("作者%v,写了一本书叫做%v", book.Author, book.Name))
})
}
Select提供四个方法,主要用来对结构体字段进行处理筛选,分别如下:
Select、SelectT:筛选对应的字段。
SelectIndexd、SelectIndexdT:筛选对应字段,这边可以拿到对应结构体的下标信息。
具体的使用例子如下:
func Select() {
bookList := MakeBook()
query := linq.From(bookList)
//筛选出结构体对应的元素
query.SelectT(func(book Book) string {
return book.Name
}).ForEachT(func(bookName string) {
fmt.Println(fmt.Sprintf("书名%v", bookName))
})
fmt.Println()
fmt.Println()
//根据下标进行返回,如果是跟下标有关的,则可以通过这个方法进行组合然后返回.
query.SelectIndexedT(func(index int, book Book) []string {
return []string{strconv.Itoa(index + 1), book.Name}
}).ForEachT(func(book []string) {
fmt.Println(fmt.Sprintf("第%v本书,书名%v", book[0], book[1]))
})
}
SelectMany主要用于多维数组或者是嵌套结构体的处理,这边提供了四个方法:
SelectMany、SelectManyT:对多维度数组进行处理,传入一个返回 linq.Query对象的方法,一次之后把二维数组扁平化为一维数组
SelectManyBy、SelectManyByT:将集合的每个元素投影到一个Query,将结果集合迭代和展平为一个集合,并在其中的每个元素上调用结果,比较厉害的一个就是拿到结构体数组中的对应子结构体,然后通过第二个方法拿到子结构和子结构体对应的结构体进行处理,具体可以看下面的代码进行理解:
func SelectMany() {
input := [][]int{{1, 2, 3}, {4, 5, 6, 7}}
//二位数组进行合并
linq.From(input).SelectManyT(
func(i []int) linq.Query {
return linq.From(i)
},
).ForEachT(func(num int) {
fmt.Println(num)
})
fmt.Println()
fmt.Println()
//三维数组进行合并
input1 := [][][]int{{{1, 2, 3}}, {{4, 5, 6, 7}, {8, 9, 10}}}
linq.From(input1).SelectManyT(
func(i [][]int) linq.Query {
return linq.From(i)
},
).SelectManyT(
func(i []int) linq.Query {
return linq.From(i)
},
).ForEachT(func(num int) {
fmt.Print(num)
fmt.Print(" ")
})
//SelectMany的主要作用是,结构体中包含数组元素,可以把数组元素取出来和结构体做相应的操作
//如果是结构体中有多个数组的操作,可以把对应的多个数组放到一个新定义的结构体数组中
fmt.Println()
men := MakeInnerData()
linq.From(men).
//第一个方法筛选出结构体对应的数组
SelectManyByT(func(man Man) linq.Query {
return linq.From(man.Pets)
},
//第二个方法这边可以拿到数组中元素对应的结构体的数据.
func(pet Pets, man Man) map[string]Pets {
return map[string]Pets{
man.Name: pet,
}
}).ForEachT(func(petWithMan map[string]Pets) {
for key, value := range petWithMan {
fmt.Println(fmt.Sprintf("%v拥有一只宠物,它的名字叫做%v", key, value.Name))
}
})
}
Join是把两个Query根据某个字段或者某种规则进行连接的操作,这边提供了两个方法
Join、JoinT:第一个入参是Query1的元素的连接字段或者规则,第二个参数是Query2对应的连接字段或者规则,当两个规则对上的时候就可以进行连接.第三个参数是 func(Query1对应的元素,Query2对应的元素),因为这边可能存在没有连接对象的情况,所以要注意处理nil的情况,第三个方法对两个对应上的元素进行处理。
具体代码例子如下:
func Join() {
//任务和动物有关联,直接找到对应的关系,没有对应关系的数据不会处理,正常情况下应该用更单一的数据来做关联
persons, pets := MakeJoinData()
query1 := linq.From(persons)
query2 := linq.From(pets)
query1.JoinT(query2,
func(person Person) string {
return person.Name
},
func(pet Pet) string {
return pet.OwnerName
},
func(person Person, pet Pet) map[string]Pet {
petMap := make(map[string]Pet)
petMap[person.Name] = pet
return petMap
},
).ForEachT(func(petMap map[string]Pet) {
for key, value := range petMap {
fmt.Println(fmt.Sprintf("%v拥有一只宠物,它的名字叫做:%v", key, value.Name))
}
})
}