How to embed and override a struct in Go - 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}}

Related

Peeking into the top of the Priority Queue in Go?

I was trying to implement a sample program using heap, and I am able to Push and Pop from the Heap. I was able to implement the Push and Pop methods and use them as follows:
import "container/heap"
type Meeting struct {
start int
end int
}
func NewMeeting(times []int) *Meeting {
return &Meeting{start: times[0], end: times[1] }
}
type PQ []*Meeting
func (pq PQ) Len() int {
return len(pq)
}
func (pq PQ) Less(i, j int) bool {
return pq[i].end < pq[j].end
}
func (pq PQ) Swap(i, j int) {
pq[i], pq[j] = pq[j], pq[i]
}
func (pq *PQ) Push(x interface{}) {
item := x.(*Meeting)
*pq = append(*pq, item)
}
func (pq *PQ) Pop() interface{} {
old := *pq
n := len(old)
item := old[n-1]
old[n-1] = nil // avoid memory leak
*pq = old[0 : n-1]
return item
}
func minMeetingRooms(intervals [][]int) int {
pq := make(PQ, 0)
heap.Init(&pq)
heap.Push(&pq, NewMeeting([]int{1, 3}))
heap.Push(&pq, NewMeeting([]int{1, 2}))
fmt.Println(heap.Pop(&pq).(*Meeting)) // I would like to log this without popping prom the Queue
return 0
}
Please see the comment in the code snippet in the minMeetingRooms function.
I would like to log the top of the Priority Queue, without actually popping it. How can I go that?
You can "peek" the element that pop() will return by returning the first element of the underlying array. (i.e. pq[0])
fmt.Println(pq[0])
you need to use the first element to peek

Wrapper around slice is doing weird things

I am probably wasting my time implementing this, but I am looking for a way to push/pop to a slice more easily, so I have this:
package h
import (
"sync"
log "github.com/sirupsen/logrus"
)
type List struct {
internalList []interface{}
mux sync.Mutex
}
func MakeList(l []interface{}) List{
return List{l, sync.Mutex{}}
}
func (l List) Add(args ...interface{}) List{
l.mux.Lock()
l.internalList = append(l.internalList, args...)
log.Info(l.internalList)
l.mux.Unlock()
return l;
}
func (l List) Push(v interface{}) List {
l.mux.Lock()
l.internalList = append(l.internalList, v)
log.Info("internal:",l.internalList);
l.mux.Unlock()
return l;
}
func (l List) Pop() interface{}{
l.mux.Lock()
length :=len(l.internalList);
log.Info("the length is:", length)
if length < 1 {
return nil;
}
last := l.internalList[length-1]
l.internalList = l.internalList[:length-1]
l.mux.Unlock()
return last;
}
func (l List) GetLength() int {
return len(l.internalList);
}
func (l List) Shift() interface{} {
l.mux.Lock()
if len(l.internalList) < 1 {
return nil;
}
first := l.internalList[0];
l.internalList = l.internalList[1:]
l.mux.Unlock()
return first;
}
func (l List) Unshift(v interface{}){
l.mux.Lock()
l.internalList = append([]interface{}{v}, l.internalList...)
l.mux.Unlock()
}
func (l List) GetValue() []interface{}{
return l.internalList
}
and then I use it like so:
package main
import (
"github.com/sirupsen/logrus"
"huru/h"
"huru/utils"
)
func main(){
x := h.List{}
x.Push(3)
logrus.Info("value:",x.GetValue())
logrus.Info("len:",x.GetLength());
logrus.Info(x.Pop());
}
but the weird thing is I get this:
INFO[0000] internal:[3]
INFO[0000] value:[]
INFO[0000] len:0
INFO[0000] the length is:0
INFO[0000] <nil>
I have no idea why 3 gets added to the slice, but then the slice length mysteriously goes to zero and when I pop() I get nil. Anybody know why that's happening?
Given the existing answer, I am wondering if there is a difference between:
func (l *List) Add(args ...interface{}) *List {
l.mux.Lock()
l.internalList = append(l.internalList, args...)
log.Info(l.internalList)
l.mux.Unlock()
return l;
}
func (l *List) Push(v interface{}) *List {
l.mux.Lock()
l.internalList = append(l.internalList, v)
log.Info("internal:",l.internalList)
l.mux.Unlock()
return l
}
and
func (l *List) Add(args ...interface{}) List {
l.mux.Lock()
l.internalList = append(l.internalList, args...)
log.Info(l.internalList)
l.mux.Unlock()
return *l;
}
func (l *List) Push(v interface{}) List {
l.mux.Lock()
l.internalList = append(l.internalList, v)
log.Info("internal:",l.internalList)
l.mux.Unlock()
return *l
}
Since your methods are mutating the data, they need to use pointer receivers:
func (l *List) Push(v interface{}) List {
...
}
Otherwise, the state will be updated on the copy of the struct, and lost after that.
More on that in Effective Go
Update: I noticed that you return the updated value from your methods. If the copy is what you actually want, you need to keep the value receivers as they are now, but then use the returned values in your calling code as well:
x = x.Push(3)

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"`
}

Priority queue and heap

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
}

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