go-linq按照时间排序

Posted lishuangquan1987

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了go-linq按照时间排序相关的知识,希望对你有一定的参考价值。

写惯了C#的linq,对集合进行各种操作,很丝滑,突然写go的时候,操作slice不知所措。
于是在github上找到了这个库:https://github.com/ahmetb/go-linq,又回到了丝滑的感觉。
但是在按照时间排序的时候,报错了。
先上代码:

package main

import (
	"fmt"
	"time"

	"github.com/ahmetb/go-linq/v3"
)

func main() 
	list := make([]Person, 0)
	list = append(list,
		Person
			Name: "tony1",
			Age:  1,
			Born: time.Date(2000, 1, 1, 8, 0, 0, 0, time.Local),
		, Person
			Name: "tony2",
			Age:  1,
			Born: time.Date(2001, 1, 1, 8, 0, 0, 0, time.Local),
		,
		Person
			Name: "tony3",
			Age:  1,
			Born: time.Date(2002, 1, 1, 8, 0, 0, 0, time.Local),
		)
	orderedList := make([]Person, 0)
	linq.From(list).OrderByDescending(func(i interface) interface  return i.(Person).Born ).ToSlice(&orderedList)
	fmt.Println(orderedList)


type Person struct 
	Name string
	Age  int
	Born time.Time


运行报如下错误:
panic: interface conversion: time.Time is not linq.Comparable: missing method CompareTo

说的是time.Time不是linq.Comparable。
查看linq.Comparable,发现定义如下:

// Comparable is an interface that has to be implemented by a custom collection
// elements in order to work with linq.
//
// Example:
// 	func (f foo) CompareTo(c Comparable) int 
// 		a, b := f.f1, c.(foo).f1
//
// 		if a < b 
// 			return -1
// 		 else if a > b 
// 			return 1
// 		
//
// 		return 0
// 	
type Comparable interface 
	CompareTo(Comparable) int

连同注释一起复制过来了,意思是要实现比较,就必须让类型实现Comparable 接口。
那么如何让time.Time实现linq.Comparable接口呢?

错误的尝试:
这还不简单,直接写一个time.Time的对象方法,这样time.Time不就自动实现了linq.Comparable接口了

func (a time.Time) CompareTo(c linq.Comparable) int 
	b := c.(time.Time)
	if a.After(b) 
		return 1
	 else if a.Equal(b) 
		return 0
	 else 
		return -1
	

But,当写完这个方法之后,发现报错了!!!

意思是,time.Time没有在main包中定义,原来go只允许拓展struct所在包的方法

正确的方式

既然time.Time没有定义在main包,那我们自己定义一种类型,在自己的类型上实现linq.Comparable这个方法,而我们自定义的类型,与time.Time肯定有着千丝万缕的关系。

C#的面向对象思想:组合优于继承
那就用组合的方式,将time.Time包装到自定义类型的里面,更改后的代码如下:

方式一

package main

import (
	"fmt"
	"time"

	"github.com/ahmetb/go-linq/v3"
)

func main() 
	list := make([]Person, 0)
	list = append(list,
		Person
			Name: "tony1",
			Age:  1,
			Born: time.Date(2000, 1, 1, 8, 0, 0, 0, time.Local),
		, Person
			Name: "tony2",
			Age:  1,
			Born: time.Date(2001, 1, 1, 8, 0, 0, 0, time.Local),
		,
		Person
			Name: "tony3",
			Age:  1,
			Born: time.Date(2002, 1, 1, 8, 0, 0, 0, time.Local),
		)
	orderedList := make([]Person, 0)
	linq.From(list).OrderByDescending(func(i interface) interface  return NewMytime(i.(Person).Born) ).ToSlice(&orderedList)
	fmt.Println(orderedList)


type Person struct 
	Name string
	Age  int
	Born time.Time


type Mytime struct 
	Time time.Time


func NewMytime(t time.Time) Mytime 
	return MytimeTime: t

func (a Mytime) CompareTo(c linq.Comparable) int 
	b := c.(Mytime)
	if a.Time.After(b.Time) 
		return 1
	 else if a.Time.Equal(b.Time) 
		return 0
	 else 
		return -1
	

方式二

package main

import (
	"fmt"
	"time"

	"github.com/ahmetb/go-linq/v3"
)

func main() 
	list := make([]Person, 0)
	list = append(list,
		Person
			Name: "tony1",
			Age:  1,
			Born: NewMytime(time.Date(2000, 1, 1, 8, 0, 0, 0, time.Local)),
		, Person
			Name: "tony2",
			Age:  1,
			Born: NewMytime(time.Date(2001, 1, 1, 8, 0, 0, 0, time.Local)),
		,
		Person
			Name: "tony3",
			Age:  1,
			Born: NewMytime(time.Date(2002, 1, 1, 8, 0, 0, 0, time.Local)),
		)
	orderedList := make([]Person, 0)
	linq.From(list).OrderByDescending(func(i interface) interface  return i.(Person).Born ).ToSlice(&orderedList)
	fmt.Println(orderedList)


type Person struct 
	Name string
	Age  int
	Born Mytime


type Mytime struct 
	Time time.Time


func NewMytime(t time.Time) Mytime 
	return MytimeTime: t

func (a Mytime) CompareTo(c linq.Comparable) int 
	b := c.(Mytime)
	if a.Time.After(b.Time) 
		return 1
	 else if a.Time.Equal(b.Time) 
		return 0
	 else 
		return -1
	

最后运行,结果跟预期的一致:

以上两种方式,都是定义一个Mytimetime.Time聚合在里面。
但是反问自己,真的不能用继承的方式吗???
于是有了第三种方式的解法:

方式三

先定义一个time.Time的类型叫CustomTime,并实现linq.Comparable接口

type CustomTime time.Time

func (a CustomTime) CompareTo(c linq.Comparable) int 
	aa := time.Time(a)
	bb := time.Time(c.(CustomTime))
	if aa.After(bb) 
		return 1
	 else if aa.Equal(bb) 
		return 0
	 else 
		return -1
	

排序的时候,强制转换为CustomTime类型:

func main() 
	list := make([]Person, 0)
	list = append(list,
		Person
			Name: "tony1",
			Age:  1,
			Born: time.Date(2000, 1, 1, 8, 0, 0, 0, time.Local),
		, Person
			Name: "tony2",
			Age:  1,
			Born: time.Date(2001, 1, 1, 8, 0, 0, 0, time.Local),
		,
		Person
			Name: "tony3",
			Age:  1,
			Born: time.Date(2002, 1, 1, 8, 0, 0, 0, time.Local),
		)
	orderedList := make([]Person, 0)
	linq.From(list).OrderByDescending(func(i interface) interface  return CustomTime(i.(Person).Born) ).ToSlice(&orderedList)
	fmt.Println(orderedList)

return CustomTime(i.(Person).Born)这里就是将time.Time强制转换为CustomTime因为它们是同一个类型
以后遇到要拓展第三方包或者系统struct的类型时,就推荐使用第三种方式

以上是关于go-linq按照时间排序的主要内容,如果未能解决你的问题,请参考以下文章

topK的3种解法

LeetCode-75.颜色分类

快速排序,排序基础

22-快速排序随机选择元素的优雅解法

八大排序总结---- 数据结构 (图解法) 面试必会! ! !

八大排序总结---- 数据结构 (图解法) 面试必会! ! !