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"`
}
Related
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}}
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]
}
}
}
}
I'm trying to implement a priority queue based on the example provided in the documentation.
Docs: priorityQueue
In short it looks like this (not everything is included):
package pq
type Item struct {
container interface{}
priority int
index int
}
type PriorityQueue []*Item
func NewItem(value interface{}, prio int) *Item {
return &Item {container: value, priority: prio}
}
func (pq PriorityQueue) Len() int {
return len(pq)
}
func (pq PriorityQueue) Less(i, j int) bool {
return pq[i].priority > pq[j].priority
}
func (pq *PriorityQueue) Swap(i, j int) {
(*pq)[i], (*pq)[j] = (*pq)[j], (*pq)[i]
(*pq)[i].index = i
(*pq)[j].index = j
}
func (pq PriorityQueue) Push(x interface{}) {
fmt.Printf("adr: %p\n", &pq)
n := len(pq)
item := x.(*Item)
item.index = n
pq = append(pq, item)
}
func (pq *PriorityQueue) Pop() interface{} {
old := *pq
n := len(old)
itm := old[n - 1]
itm.index = -1
*pq = old[0 : n-1]
return itm.container
}
The main.go file:
func main() {
q := pq.PriorityQueue{}
heap.Init(q)
fmt.Printf("\nAdr: %p\n", &q)
q.Push(pq.NewItem("h", 2))
for i := 0; i < 5; i++ {
item := pq.NewItem("test", i * 13 % 7)
heap.Push(q, item)
}
for q.Len() > 0 {
fmt.Println("Item: " + heap.Pop(q).(string))
}
}
As you can see when comparing to the example I do not use pointers since doing that will give me a compile error telling me that my priority queue does not implement the interface properly.
This leaves me with the following problem when I do:
heap.Push(q, item)
that the item is not appended to the queue.
I've tried to write out the queues pointer address and it shows different addresses. This explains why it does not work, but souldn't slices not be reference types a long with maps?
And more specificly: How do i solve my problem?
Hope you can help!
Edit: Added full code and error: cannot use q (type pq.PriorityQueue) as type heap.Interface in function argument:
pq.PriorityQueue does not implement heap.Interface (Pop method has pointer receiver)
As the example code shows, the Push method must have a pointer receiver.
The trick is that all the calls to heap.XXX functions, require that you pass your heap in as a pointer (e.g.: heap.Init(&pq)). This is not the case in the code you posted. Here is a working version of your code. You can run it on the Go playground.
Note that in this code, I explicitly initialize the queue as a pointer: q := new(PriorityQueue). And this is what I pass in to all the heap functions.
The confusion here arises mostly because you are essentially implementing 2 interfaces.
The heap.Interface and the sort.Interface (The latter is part of the prior's type definition). But the sort interface is fine with non-pointer receivers, while the other one is not.
package main
import "fmt"
import "container/heap"
func main() {
q := new(PriorityQueue)
heap.Init(q)
fmt.Printf("\nAdr: %p\n", &q)
q.Push(NewItem("h", 2))
for i := 0; i < 5; i++ {
heap.Push(q, NewItem("test", i*13%7))
}
for q.Len() > 0 {
fmt.Println("Item: " + heap.Pop(q).(string))
}
}
type Item struct {
container interface{}
priority int
index int
}
type PriorityQueue []*Item
func NewItem(value interface{}, prio int) *Item {
return &Item{container: value, priority: prio}
}
func (pq PriorityQueue) Len() int {
return len(pq)
}
func (pq PriorityQueue) Less(i, j int) bool {
return pq[i].priority > pq[j].priority
}
func (pq PriorityQueue) Swap(i, j int) {
pq[i], pq[j] = pq[j], pq[i]
pq[i].index = i
pq[j].index = j
}
func (pq *PriorityQueue) Push(x interface{}) {
fmt.Printf("adr: %p\n", pq)
n := len(*pq)
item := x.(*Item)
item.index = n
*pq = append(*pq, item)
}
func (pq *PriorityQueue) Pop() interface{} {
old := *pq
n := len(old)
itm := old[n-1]
itm.index = -1
*pq = old[0 : n-1]
return itm.container
}
I have following code in Go:
type Foo struct { Id int }
type Bar struct { Id int }
func getIdsFoo(foos []Foo) {
ids = make([]int, len(foos))
// iterate and get all ids to ids array
}
func getIdsBar(bars []Bar) {
ids = make([]int, len(bars))
// iterate and get all ids to ids array
}
Is there a clever way to create a function getIds([]Idable) that can take any struct that have method GetId() implemented?
type Identifiable interface {
GetId() int
}
func GatherIds(ys []Identifiable) []int {
xs := make([]int, 0, len(ys))
for _, i := range ys {
xs = append(xs, i.GetId())
}
return xs
}
sort uses a design patter that might help you.
Create a function that works on an slice-like interface. Then create new types based off of a slice of your concrete types.
Hopefully, the code is more clear than my description. http://play.golang.org/p/TL6yxZZUWT
type IdGetter interface {
GetId(i int) int
Len() int
}
func GetIds(ig IdGetter) []int {
ids := make([]int, ig.Len())
for i := range ids {
ids[i] = ig.GetId(i)
}
return ids
}
type Foo struct{ Id int }
type Bar struct{ Id int }
type FooIdGetter []Foo
func (f FooIdGetter) GetId(i int) int {
return f[i].Id
}
func (f FooIdGetter) Len() int {
return len(f)
}
type BarIdGetter []Bar
func (b BarIdGetter) GetId(i int) int {
return b[i].Id
}
func (b BarIdGetter) Len() int {
return len(b)
}
func main() {
var f = []Foo{{5}, {6}, {7}}
var b = []Bar{{10}, {11}, {12}}
fmt.Println("foo ids:", GetIds(FooIdGetter(f)))
fmt.Println("bar ids:", GetIds(BarIdGetter(b)))
}
There is still a bit more boilerplate than is pleasant, (Go generics... someday). It's greatest advantage is that new methods do not need to be added to Foo, Bar, or any future type you may need to work with.
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.