How to sort by time.Time - go

I am trying to sort struct in Go by its member which is of type time.Time.
the structure is as follows.
type reviews_data struct {
review_id string
date time.Time
score int
firstname string
anonymous bool
review_text string
title_text string
rating float64
upcount int
}
I have the below functions for sorting
type timeSlice []reviews_data
// Forward request for length
func (p timeSlice) Len() int {
return len(p)
}
// Define compare
func (p timeSlice) Less(i, j int) bool {
return p[i].date.Before(p[j].date)
}
// Define swap over an array
func (p timeSlice) Swap(i, j int) {
p[i], p[j] = p[j], p[i]
}
A map is defined as follows
var reviews_data_map = make(map[string]reviews_data)
After the map gets filled with values,sorting of the map by values is done as below
//Sort the map by date
date_sorted_reviews := make(timeSlice, 0, len(reviews_data_map))
for _, d := range reviews_data_map {
date_sorted_reviews = append(date_sorted_reviews, d)
}
sort.Sort(date_sorted_reviews)
The problem is that the result is not sorted.Can anyone tell me what the problem is.

Go 1.8 and above:
sort.Slice(timeSlice, func(i, j int) bool {
return timeSlice[i].date.Before(timeSlice[j].date)
})

It looks sorted to me:
package main
import (
"fmt"
"sort"
"time"
)
type reviews_data struct {
review_id string
date time.Time
score int
firstname string
anonymous bool
review_text string
title_text string
rating float64
upcount int
}
type timeSlice []reviews_data
func (p timeSlice) Len() int {
return len(p)
}
func (p timeSlice) Less(i, j int) bool {
return p[i].date.Before(p[j].date)
}
func (p timeSlice) Swap(i, j int) {
p[i], p[j] = p[j], p[i]
}
func main() {
var reviews_data_map = make(map[string]reviews_data)
reviews_data_map["1"] = reviews_data{date: time.Now().Add(12 * time.Hour)}
reviews_data_map["2"] = reviews_data{date: time.Now()}
reviews_data_map["3"] = reviews_data{date: time.Now().Add(24 * time.Hour)}
//Sort the map by date
date_sorted_reviews := make(timeSlice, 0, len(reviews_data_map))
for _, d := range reviews_data_map {
date_sorted_reviews = append(date_sorted_reviews, d)
}
fmt.Println(date_sorted_reviews)
sort.Sort(date_sorted_reviews)
fmt.Println(date_sorted_reviews)
}
Output:
[{ {63393534000 0 0x1ba3e0} 0 false 0 0} { {63393490800 0 0x1ba3e0} 0 false 0 0} { {63393577200 0 0x1ba3e0} 0 false 0 0}]
[{ {63393490800 0 0x1ba3e0} 0 false 0 0} { {63393534000 0 0x1ba3e0} 0 false 0 0} { {63393577200 0 0x1ba3e0} 0 false 0 0}]

This can be done below go 1.8 without the extra type and map in the accepted answer.
package main
import (
"fmt"
"time"
"sort"
)
type reviews_data struct {
review_id string
date time.Time
}
func main() {
fmt.Println("Sort Example")
var listOfReviews = make([]reviews_data, 0)
listOfReviews = append(listOfReviews, reviews_data{review_id: "1",date:time.Now()})
listOfReviews = append(listOfReviews, reviews_data{review_id: "2",date: time.Now().AddDate(0, 0, 7*1)})
listOfReviews = append(listOfReviews, reviews_data{review_id: "1",date: time.Now().AddDate(0, 0, 7*-1)})
sort.Slice(listOfReviews, func(i, j int) bool { return listOfReviews[i].date.Before(listOfReviews[j].date) })
}

sorting dates
type Location struct {
Lat float64 `json:"lat"`
Lng float64 `json:"lng"`
Thetime time.Time `json:"thetime"`
}
func sorttime(dat []Location) {
for i := 0; i < len(dat); i++ {
for j := i + 1; j < len(dat); j++ {
if dat[i].Thetime.Unix() < dat[j].Thetime.Unix() {
dat[i], dat[j] = dat[j], dat[i]
}
}
}
}

Related

How to embed and override a struct in Go

I am constructing the min/max heaps of ints to satisfy the interface from container/heap.
The min heap works well such as
type MinHeapInt []int
func (h MinHeapInt) Len() int {
return len(h)
}
func (h MinHeapInt) Less(i, j int) bool {
return h[i] < h[j]
}
func (h MinHeapInt) Swap(i, j int) {
h[i], h[j] = h[j], h[i]
}
func (h *MinHeapInt) Peek() interface{} {
return (*h)[0]
}
func (h *MinHeapInt) Push(x interface{}) {
*h = append(*h, x.(int))
}
func (h *MinHeapInt) Pop() interface{} {
length := len(*h)
res := (*h)[length - 1]
*h = (*h)[0 : length - 1]
return res
}
Now I am trying to develop the max heap by only overriding the Less method.
The first solution does not work since it cannot find the array
type MaxHeapInt struct {
MinHeapInt
}
func (h MaxHeapInt) Less(i, j int) bool {
return h[i] > h[j]
}
The second solution only keeps the Less method.
type MaxHeapInt MinHeapInt
func (h MaxHeapInt) Less(i, j int) bool {
return h[i] > h[j]
}
Wonder if there is anyway to get around. Thanks!
Your first solution is trying to index the MaxHeapInt struct, not the MinHeapInt slice.
type MaxHeapInt struct {
MinHeapInt
}
func (h MaxHeapInt) Less(i, j int) bool {
return h.MinHeapInt[i] > h.MinHeapInt[j]
}
If you want them to be initialized the same, then create a partial heap implementation, and wrap in the desired struct (similar to the wrapper example in the sort package).
type Max struct{ IntHeap }
func (h Max) Less(i, j int) bool {
return h.IntHeap[i] > h.IntHeap[j]
}
type Min struct{ IntHeap }
func (h Min) Less(i, j int) bool {
return h.IntHeap[i] < h.IntHeap[j]
}
type IntHeap []int
func (h IntHeap) Len() int { return len(h) }
func (h IntHeap) Swap(i, j int) { h[i], h[j] = h[j], h[i] }
func (h *IntHeap) Peek() interface{} { return (*h)[0] }
func (h *IntHeap) Push(x interface{}) {
*h = append(*h, x.(int))
}
func (h *IntHeap) Pop() interface{} {
length := len(*h)
res := (*h)[length-1]
*h = (*h)[0 : length-1]
return res
}
// Now these can be initialized like
// Min{IntHeap{1, 2, 3}}
// Max{IntHeap{1, 2, 3}}

How can I compare struct data and interface data in Golang?

I am trying to create a generic Binary Tree in Golang. How can I compare data from an interface and input data in the code? Here is an example of what I am trying to do. The comparison that is giving me trouble is this
} else if cur.data < data {
-
package DSAA
type TreeNode struct {
data interface{}
right *TreeNode
left *TreeNode
}
type BinarySearchTree struct {
root *TreeNode
}
func BSTCreate() *BinarySearchTree {
return &BinarySearchTree{nil}
}
func (b *BinarySearchTree) Insert(cur TreeNode, data interface{}) *BinarySearchTree {
if &cur == nil {
cur := &TreeNode{data, nil, nil}
} else if cur.data < data {
b = b.Insert(*cur.left, data)
} else {
b = b.Insert(*cur.right, data)
}
return b
}
You have some options:
1- Using runtime type switch:
package main
import (
"fmt"
)
func main() {
fmt.Println(Less(1, 2)) // true
fmt.Println(Less("AB", "AC")) // true
}
func Less(a, b interface{}) bool {
switch v := a.(type) {
case int:
w := b.(int)
return v < w
case string:
w := b.(string)
return v < w
}
return false
}
then replace } else if cur.data < data { with
} else if Less(cur.data , data) {
2- Using Comparer interface:
package main
import (
"fmt"
)
type Comparer interface {
// Less reports whether the element is less than b
Less(b interface{}) bool
}
func main() {
a, b := Int(1), Int(2)
fmt.Println(a.Less(b)) // true
c, d := St("A"), St("B")
fmt.Println(c.Less(d)) // true
}
type Int int
func (t Int) Less(b interface{}) bool {
if v, ok := b.(Int); ok {
return int(t) < int(v)
}
return false
}
type St string
func (t St) Less(b interface{}) bool {
if v, ok := b.(St); ok {
return string(t) < string(v)
}
return false
}
3- Using reflect

Sort by dynamic field in go lang

So I'm struggling to figure out how to sort following structure by "status" field (asc, desc)
type CampaignStatus struct {
Campaign CampaignData
Status string `json:"status" bson:"status"`
}
type CampaignsPagination struct {
Pagination PageMetadata `json:"pagination"`
Campaigns []CampaignStatus `json:"campaigns"`
}
Example json of full campaigns pagination:
"pagination": {
"page": 1,
"per_page": 15,
"page_count": 1,
"total_count": 4
},
"campaigns": [
{
"Campaign": {
"_id": "57597fc6799e0fe41d0eede6",
"name": "Test campaign",
"description": "Just test campaign"
"isEmail": true
},
"status": "expired"
},
...
}
So my function is retuting variable ret := &CampaignsPagination{} which is filled with data from mongoDB but status is determinated by other stuff in realtime. So reflect package is saying that I'm trying to sort type of *CampaignsPagination and everything what I use pretty much ends with errors like "type CampaignsPagination does not support indexing" (using sort packag) any hints are more then welcome
Update:
How I try to sort this (but it won't compile due to (type *CampaignsPagination does not support indexing
func (a *CampaignsPagination) Len() int {
return len(a)
}
func (a *CampaignsPagination) Swap(i, j int) {
a[i], a[j] = a[j], a[i]
}
func (a *CampaignsPagination) Less(i, j int) bool {
if a[i].Status < a[j].Status {
return true
}
if a[i].Status > a[j].Status {
return false
}
return a[i].Status < a[j].Status
}
Usually sorting is defined on a slice. You try to define sorting on your CampaignsPagination struct type.
This can also be done, but it's a little unusal (e.g. what would you do if you decide you want to have another order based on another field?). Since your receiver a is not a slice but a (pointer to a) wrapper struct, when indexing and returning the length, use the slice a.Campaigns. Also string values are comparable and ordered (lexically byte-wise). So you can simply compare CampaignStatus.Status values and return the result in Less().
func (a *CampaignsPagination) Len() int {
return len(a.Campaigns)
}
func (a *CampaignsPagination) Swap(i, j int) {
a.Campaigns[i], a.Campaigns[j] = a.Campaigns[j], a.Campaigns[i]
}
func (a *CampaignsPagination) Less(i, j int) bool {
return a.Campaigns[i].Status < a.Campaigns[j].Status
}
A more logical solution would be to define the sorting on a slice, e.g.:
type CampaignStatusSort []CampaignStatus
func (c CampaignStatusSort) Len() int { return len(c) }
func (c CampaignStatusSort) Swap(i, j int) { c[i], c[j] = c[j], c[i] }
func (c CampaignStatusSort) Less(i, j int) bool { return c[i].Status < c[j].Status }
And then if you have a value of type *CampaignsPagination, you can sort the campaigns like this:
cp := &CampaignsPagination{} // Init struct
sort.Sort(CampaignStatusSort(cp.Campaigns))
There is no one to one relationship between CampaignsPagination and Status. CampaignsPagination has a slice of CampaignStatus as a field; means CampaignsPagination has many Statuses.
So I assume that you want to sort the field Campaigns []CampaignStatus. Your code is almost correct; for CampaignsPagination to implement the interface sort.Interface:
func (x *CampaignsPagination) Len() int {
return len(x.Campaigns)
}
func (x *CampaignsPagination) Swap(i, j int) {
a := x.Campaigns
a[i], a[j] = a[j], a[i]
}
func (x *CampaignsPagination) Less(i, j int) bool {
a := x.Campaigns
if a[i].Status < a[j].Status {
return true
}
if a[i].Status > a[j].Status {
return false
}
return a[i].Status < a[j].Status
}
But it would be more logical to introduce a sortable type:
type Statuses []CampaignStatus
func (a Statuses) Len() int {
return len(a)
}
func (a Statuses) Swap(i, j int) {
a[i], a[j] = a[j], a[i]
}
func (a Statuses) Less(i, j int) bool {
if a[i].Status < a[j].Status {
return true
}
if a[i].Status > a[j].Status {
return false
}
return a[i].Status < a[j].Status
}
And then use this as the field Campaigns:
type CampaignsPagination struct {
Pagination PageMetadata `json:"pagination"`
Campaigns Statuses `json:"campaigns"`
}

Append slice to slice of slices

I have data structure:
type PosList []int
type InvertedIndex struct {
Capacity int
Len int
IndexList []PosList
}
I have problem with Add method:
func (ii *InvertedIndex) Add(posList PosList, docId int) {
if ii.Len == ii.Capacity {
newIndexList := make([]PosList, ii.Len, (ii.Capacity+1)*2)
for i := 0; i < ii.Len; i++ {
newIndexList[i] = make([]int, len(ii.IndexList[i]))
copy(newIndexList[i], ii.IndexList[i])
}
ii.IndexList = newIndexList
}
ii.IndexList = ii.IndexList[0 : ii.Len+2]
ii.IndexList[docId] = posList
return
}
Or, i try something like this:
func (ii *InvertedIndex) Add(posList PosList, docId int) {
if ii.Len == ii.Capacity {
newIndexList := make([]PosList, ii.Len, (ii.Capacity+1)*2)
copy(newIndexList, ii.IndexList)
ii.IndexList = newIndexList
}
ii.IndexList = ii.IndexList[0 : ii.Len+2]
ii.IndexList[docId] = posList
return
}
Both of them don't work, may be someone can explain how can i append a slice to structure like this.
You question is confusing. I assume that you are trying to create a typical inverted index. In which case, you probably want to do something like this:
package main
import "fmt"
type DocId int
type Positions []int
type docIndex struct {
docId DocId
positions Positions
}
type InvertedIndex struct {
docIndexes []docIndex
}
func New() *InvertedIndex {
return &InvertedIndex{}
}
func (ii *InvertedIndex) Add(docId DocId, positions Positions) {
for i, di := range (*ii).docIndexes {
if di.docId == docId {
di.positions = append(di.positions, positions...)
(*ii).docIndexes[i] = di
return
}
}
di := docIndex{
docId: docId,
positions: positions,
}
(*ii).docIndexes = append((*ii).docIndexes, di)
}
func main() {
ii := New()
docId := DocId(11)
positions := Positions{42, 7}
ii.Add(docId, positions)
positions = Positions{21, 4}
ii.Add(docId, positions)
docId = DocId(22)
positions = Positions{84, 14}
ii.Add(docId, positions)
fmt.Printf("%+v\n", *ii)
}
Output:
{docIndexes:[{docId:11 positions:[42 7 21 4]} {docId:22 positions:[84 14]}]}
The statement:
di.positions = append(di.positions, positions...)
appends a slice to a slice.
References:
Appending to and copying slices
Arrays, slices (and strings): The mechanics of 'append'
inverted index
I'm not sure I fully understand what you're doing, however something like this should just work fine, replacing the slice with a map :
type PosList []int
type InvertedIndex struct {
Len int
IndexList map[int]PosList
}
func (ii *InvertedIndex) Add(posList PosList, docId int) {
if ii.IndexList == nil {
ii.IndexList = make(map[int]PosList)
}
if _, ok := ii.IndexList[docId]; ok {
ii.IndexList[docId] = append(ii.IndexList[docId], posList...)
} else {
ii.IndexList[docId] = posList
}
ii.Len = len(ii.IndexList)
}

not able to search for an item in a slice of structs

Pulling my hair out on this one. Any help would be greatly appreciated. I've created a struct called Person, and a custom slice type called PersonList that holds *Person. I'm able to populate and sort the slice, but when it comes to searching the slice I'm getting weird results: search is able to find some items, but not others.
type Person struct {
id int
name string
}
type PersonList []*Person
func (pl *PersonList) Add(p *Person) {
*pl = append(*pl, p)
}
func (pl PersonList) Search(id int) int {
f := func(i int) bool { return pl[i].id == id }
return sort.Search(len(pl), f)
}
func (pl PersonList) Sort() {
sort.Sort(pl)
}
func (pl PersonList) IsSorted() bool {
return sort.IsSorted(pl)
}
func (pl PersonList) Len() int {
return len(pl)
}
func (pl PersonList) Swap(i, j int) {
pl[i], pl[j] = pl[j], pl[i]
}
func (pl PersonList) Less(i, j int) bool {
return pl[i].id < pl[j].id
}
func (p Person) String() string {
return "id=" + strconv.Itoa(p.id) + " name=" + p.name + "\n"
}
func main() {
plist := make(PersonList, 0)
plist.Add(&Person{839, "Bob"})
plist.Add(&Person{23, "Larry"})
plist.Add(&Person{93420, "Jane"})
plist.Add(&Person{3, "Sam"})
plist.Add(&Person{7238, "Betty"})
fmt.Printf("plist=%v\n", plist)
plist.Sort()
fmt.Printf("plist=%v\n", plist)
fmt.Printf("3=%d\n", plist.Search(3))
fmt.Printf("23=%d\n", plist.Search(23))
fmt.Printf("839=%d\n", plist.Search(839))
fmt.Printf("7238=%d\n", plist.Search(7238))
fmt.Printf("93420=%d\n", plist.Search(93420))
}
And here is the output:
plist=[id=839 name=Bob
id=23 name=Larry
id=93420 name=Jane
id=3 name=Sam
id=7238 name=Betty
]
plist=[id=3 name=Sam
id=23 name=Larry
id=839 name=Bob
id=7238 name=Betty
id=93420 name=Jane
]
3=5
23=5
839=2
7238=5
93420=4
The search method was able to find id's 839 and 93420, but couldn't find the others.
Any ideas? Thanks very much!
For example,
package main
import (
"fmt"
"sort"
"strconv"
)
type Person struct {
id int
name string
}
type PersonList []*Person
func (pl *PersonList) Add(p *Person) {
*pl = append(*pl, p)
}
func (pl PersonList) Search(id int) int {
f := func(i int) bool { return pl[i].id >= id }
if i := sort.Search(len(pl), f); pl[i].id == id {
return i
}
return -1
}
func (pl PersonList) Sort() {
sort.Sort(pl)
}
func (pl PersonList) IsSorted() bool {
return sort.IsSorted(pl)
}
func (pl PersonList) Len() int {
return len(pl)
}
func (pl PersonList) Swap(i, j int) {
pl[i], pl[j] = pl[j], pl[i]
}
func (pl PersonList) Less(i, j int) bool {
return pl[i].id < pl[j].id
}
func (p Person) String() string {
return "id=" + strconv.Itoa(p.id) + " name=" + p.name + "\n"
}
func main() {
plist := make(PersonList, 0)
plist.Add(&Person{839, "Bob"})
plist.Add(&Person{23, "Larry"})
plist.Add(&Person{93420, "Jane"})
plist.Add(&Person{3, "Sam"})
plist.Add(&Person{7238, "Betty"})
fmt.Printf("plist=%v\n", plist)
plist.Sort()
fmt.Printf("plist=%v\n", plist)
fmt.Printf("3=%d\n", plist.Search(3))
fmt.Printf("23=%d\n", plist.Search(23))
fmt.Printf("839=%d\n", plist.Search(839))
fmt.Printf("7238=%d\n", plist.Search(7238))
fmt.Printf("93420=%d\n", plist.Search(93420))
}
Output:
plist=[id=839 name=Bob
id=23 name=Larry
id=93420 name=Jane
id=3 name=Sam
id=7238 name=Betty
]
plist=[id=3 name=Sam
id=23 name=Larry
id=839 name=Bob
id=7238 name=Betty
id=93420 name=Jane
]
3=0
23=1
839=2
7238=3
93420=4
I fixed your PersonList Search method.
Package sort
func Search
func Search(n int, f func(int) bool) int
Search uses binary search to find and return the smallest index i in
[0, n) at which f(i) is true, assuming that on the range [0, n), f(i)
== true implies f(i+1) == true. That is, Search requires that f is false for some (possibly empty) prefix of the input range [0, n) and
then true for the (possibly empty) remainder; Search returns the first
true index. If there is no such index, Search returns n. (Note that
the "not found" return value is not -1 as in, for instance,
strings.Index). Search calls f(i) only for i in the range [0, n).
A common use of Search is to find the index i for a value x in a
sorted, indexable data structure such as an array or slice. In this
case, the argument f, typically a closure, captures the value to be
searched for, and how the data structure is indexed and ordered.
For instance, given a slice data sorted in ascending order, the call
Search(len(data), func(i int) bool { return data[i] >= 23 }) returns
the smallest index i such that data[i] >= 23. If the caller wants to
find whether 23 is in the slice, it must test data[i] == 23
separately.
Searching data sorted in descending order would use the <= operator
instead of the >= operator.

Resources