Sort a table in golang - sorting

I have table in golang. I need to sort it based on a particular column. Can someone help me to proceed?
table := ui.Table([]string{"SI No","Name","ID","status","submitted-at"})
strs := dat["resources"].([]interface{})
var ln int = 20
i:=0
for i < ln {
table.Add(strconv.Itoa(i+1), metadataName , metadataID, metadataStatus, metadataSubmittedAt)
i = i + 1
}

The sort package on the standard library includes an interface that if you implement it for any type then it can be sorted using the sort.Sort() function.
Even if the ui.Table object is from a package or library you can't modify, you can always declare a new type using ui.Table as it's base and implement the sort.Interface yourself, something like:
type myTable ui.Table
func (m myTable) Len() int { return len(m) }
func (m myTable) Swap(i, j int) { m[i], m[j] = m[j], m[i] }
func (m myTable) Less(i, j int) bool { return m[i].col() < m[j].col() }
Or you know some implementation that makes sense for the Table type. Here I'm assuming that your rows have a function col() that returns the value of the column you are using to sort for that row and that Table is a slice of rows which is probably not the case.
I wish I could help more but it's not possible to help you with any implementation details if you don't give any details about ui.Table.

Related

Sorting a slice of integers

My intention is to sort the values given in the slice of ints . I do not want to use the sort package and want to implement the sort function . The issue is when I try to use a index to compare the slice elements i get out of bounds error . What is correct way to modify a slice ?
func sortSlice( sli []int ) {
j := 0
i := 1
for range sli {
if( sli[j] > sli[j+1] ) {
var temp int = sli[j];
sli[i] = sli[j]
sli[j] = temp
}
j++
}
}
You range over sli meaning you iterate len(sli) times so j goes from 0 to len(sli)-1. Now you compare element j with element j+1. For the last iteration this means you compare element len(sli)-1 with element len(sli). This last index is the problem. There is no element len(sli) because sli's indices go from 0 to len(sli)-1.
Also note that in Go you can say sli[i], sli[j] = sli[j], sli[i] to swap two items. That said, your code cannot work since there is no i defined anywhere.
Next on the list of issues is that this is not all of the bubble algorithm that I think you are going for. You only iterate over the slice once but this will not sort it. You would have to repeat the loop you have until no more swaps happen.
If I understand it right, you want to do your custom implementation, but not sure why don't want to use sort package. You can do custom sorting by overriding go#interface.
For example
You can write a custom sort in go and call it with the sort package. basically you can override sort function for interface and can change the behaviour according to your needs. you can create a struct that takes in your data, as per below example and override the functions Len() , Swap() , Less()
type Sortslice struct {
Sli []int
}
func (s Sortslice) Len() int {
return len(s.Sli)
}
func (s Sortslice) Swap(i, j int) {
s.Sli[i], s.Sli[j] = s.Sli[j], s.Sli[i]
}
func (s Sortslice) Less(i, j int) bool {
if s.Sli[i] > s.Sli[j] {
return true
} else {
return false
}
}
After making the structure you can pass your data into it and call the sort method over the []interface using sort.sort() function. this will use your logic to sort the slice.
var data = []int{5,6,8,1,9,10}
sortedSlice := Sortslice{data}
sort.Sort(sortedSlice);
It's better to use sort.Sort since it takes care like what to do (use merge sort, quick sort).
But if you want to do everything by yourself follow the source code of sort.sort() and in a similar manner write your custom things
source : https://yourbasic.org/golang/how-to-sort-in-go/

How to loop through UUID items

How do I loop through a slice composed of UUIDS? My values comes from db via rows.Next()
Here's how I'm appending my uuid values to my slice (really don't know if its proper)
type Images struct {
image_id uuid.UUID `gorm:"type:uuid;primary_key;"`
}
var new_images []Images
for olds.Next() {
olds.Scan(&oldimages.image_id)
new_images = append(new_images , Images{image_id: oldimages.image_id})
}
olds here is the rows im getting from gorm Rows
olds, err := db.Raw("SELECT images_received.image_id FROM old_pics").Rows()
defer olds.Close()
Heres the function in looping I was given but its for int i dont know how to use this for uuid:
func islice(s []int, n int, f func([]int)) {
for i := 0; i < len(s); i += n {
var section []int
if i > len(s)-n {
section = s[i:]
} else {
section = s[i : i+n]
}
f(section)
}
}
Any idea how I do this? Currently for uuid im using the "github.com/satori/go.uuid" lib
I got the function from another SO question, My goal is to iterate over the rows, but rows.Next() doesnt allow that I guess in order to do that I thought I needed to append them into a slice, so I can get them by fours.
Hence leading to this question.
All you need to do is replace []int with []uuid.UUID everywhere in your islice function, including the parameter types. The functionality of islice() is not bound to []int if thats what your problem is.

Can we write a generic array/slice deduplication in go?

Is there a way to write a generic array/slice deduplication in go, for []int we can have something like (from http://rosettacode.org/wiki/Remove_duplicate_elements#Go ):
func uniq(list []int) []int {
unique_set := make(map[int] bool, len(list))
for _, x := range list {
unique_set[x] = true
}
result := make([]int, len(unique_set))
i := 0
for x := range unique_set {
result[i] = x
i++
}
return result
}
But is there a way to extend it to support any array? with a signature like:
func deduplicate(a []interface{}) []interface{}
I know that you can write that function with that signature, but then you can't actually use it on []int, you need to create a []interface{} put everything from the []int into it, pass it to the function then get it back and put it into a []interface{} and go through this new array and put everything in a new []int.
My question is, is there a better way to do this?
While VonC's answer probably does the closest to what you really want, the only real way to do it in native Go without gen is to define an interface
type IDList interface {
// Returns the id of the element at i
ID(i int) int
// Returns the element
// with the given id
GetByID(id int) interface{}
Len() int
// Adds the element to the list
Insert(interface{})
}
// Puts the deduplicated list in dst
func Deduplicate(dst, list IDList) {
intList := make([]int, list.Len())
for i := range intList {
intList[i] = list.ID(i)
}
uniques := uniq(intList)
for _,el := range uniques {
dst.Insert(list.GetByID(el))
}
}
Where uniq is the function from your OP.
This is just one possible example, and there are probably much better ones, but in general mapping each element to a unique "==able" ID and either constructing a new list or culling based on the deduplication of the IDs is probably the most intuitive way.
An alternate solution is to take in an []IDer where the IDer interface is just ID() int. However, that means that user code has to create the []IDer list and copy all the elements into that list, which is a bit ugly. It's cleaner for the user to wrap the list as an ID list rather than copy, but it's a similar amount of work either way.
The only way I have seen that implemented in Go is with the clipperhouse/gen project,
gen is an attempt to bring some generics-like functionality to Go, with some inspiration from C#’s Linq and JavaScript’s underscore libraries
See this test:
// Distinct returns a new Thing1s slice whose elements are unique. See: http://clipperhouse.github.io/gen/#Distinct
func (rcv Thing1s) Distinct() (result Thing1s) {
appended := make(map[Thing1]bool)
for _, v := range rcv {
if !appended[v] {
result = append(result, v)
appended[v] = true
}
}
return result
}
But, as explained in clipperhouse.github.io/gen/:
gen generates code for your types, at development time, using the command line.
gen is not an import; the generated source becomes part of your project and takes no external dependencies.
You could do something close to this via an interface. Define an interface, say "DeDupable" requiring a func, say, UniqId() []byte, which you could then use to do the removing of dups. and your uniq func would take a []DeDupable and work on it

How to create a literal slice of an alias to a builtin type in Go

I have some golang code that manipulates slices of an interface type (Comparable). To test my code, I want to create some fake data and operate on it. However, I'm having trouble doing this in a way that is not incredibly tedious. The only thing I can think to do is create a new type for testing (in this case an alias of type int) that satisfies the Comparable interface, and then feed my tests literal slices of that type. I envision it looking something like the following:
type Comparable interface {
LT(Comparable) bool
AsFloat() float64
}
type testInt int
func (self testInt) LT(other Comparable) bool {
return float64(self) < other.AsFloat()
}
func (self testInt) AsFloat() float64 {
return float64(self)
}
func TestAFunction(t *testing.T) {
FunctionToTest([]Comparable{7, 4, 2, 1})
....
}
However, with this example, the compiler will complain that type int cannot be used as a Comparable. I understand why this is happening, but I'm not sure how to solve it. First, I don't know how to create a literal of type testInt. Second, I have to write a significant number of these functions. Working with literal ints is far more convenient for my purposes.
Is there a way to work with type aliases of builtin types such that the compiler can correctly infer the correct type of literals with a minimum of code?
Additionally, is there perhaps a better way to accomplish what I am trying to do, i.e., generate hard data that satisfies an interface for use in testing?
func NewWhatevers(a ...int) (r []Whatever) {
r = make([]Whatever, len(a))
for i, v := range a {
r[i] = Whatever(v)
}
return
}
...
myWhatevers := NewWhatevers(7, 4, 2, 1)
There are a number of ways to accomplish this. The problem, as you correctly state, is that the Go compiler cannot automatically convert int to Comparable (since doing so would require finding all possible equivalent types, and figuring out which of those equivalent types satisfy the Comparable interface, and then if there are more than one... you get the idea). Thus, you'll have to do one of two things:
Write an explicit type conversion:
FunctionToTest([]Comparable{ testInt(7), testInt(4), testInt(2), testInt(1) })
However, if you need a lot of literals, this could get really annoying. Thus, you could also:
Write a function to convert []int to []Comparable:
func intToComparable(i []int) []Comparable {
c := make([]Comparable, len(i))
for i, v := range i {
c[i] = testInt(v)
}
return c
}
and then you'd only have to do:
FunctionToTest(intToComparable([]int{ 7, 4, 2, 1 }))
Additionally, is there perhaps a better way to accomplish what I am trying to do, i.e., generate hard data that satisfies an interface for use in testing?
Maybe. The problem you encountered is that []Comparable and []testInt are fundamentally different and cannot be exchanged as the underlying representation in memory is different.
If your code is less about individual item which are Comparable but more about slices of items which can be compared than you could refactor your code to work on whole Slices.
Have a look at how package sort does this: It doesn't operate on a slice of comparables but on a "comparable slice".
// FloatOrder is a slice with comparable and float-convertible elements
type FloatOrder interface {
Less(i, j int) bool // Compare element i and j and return true first is less than the other
Float(i int) float64 // Return element i as a float64
}
type testInts []int
func (n testInts) Less(i, j int) bool {return n[i] < n[j]}
func (n testInts) Float(i int) float64 { return float64(n[i]) }
func FunctionTotest(fo FloatOrder) { ... }
func TestAFunction(t *testing.T) {
FunctionToTest(testInts{1,2,3,4})
....
}
(Completely untested, illustration-only code)

How to order a list of different struct types in go

I've only been working with Go for a couple of days. I have a small variety of different structure types defined, each of which contains a date.
Somehow I need to process those structures in date order, but that ordering has to span across the multiple different structure types. In a dynamically typed language like Python, it's easy to just create a hash of all the objects keyed by date (or hash of lists if they're not unique). In C, I can use unions of pointers or void*. But I'm stuck as to how do this in Go.
I guess I could keep a sorted list of each type and do a manual mergesort as I go. Seems klunky?
What I've read about handling this sort of situation seems to point to using interfaces, but I don't really see how to use them in this situation.
For the sake of argument, let's say I have something like:
type A struct {
Date string
Info string
}
type B struct {
Date string
Info int
}
(Though in practice there are more structures, and they are more complex with multiple fields), and just need to print in date order the contents of an (unsorted) array of each of them.
Is there some way to create a list (date, pointer) pairs to a non-uniform object type?
Per first suggestion below:
package main
import "fmt"
type A struct {
Date string
Info string
}
func (x *A) GetDate() string {
return x.Date
}
type B struct {
Date string
Info int
}
func (x *B) GetDate() string {
return x.Date
}
type Dater interface {
GetDate() string
}
type Daters []Dater
func (s Daters) Len() int { return len(s) }
func (s Daters) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
type ByDate struct{ Daters }
func (s ByDate) Less(i, j int) bool {
return s.Daters[i].GetDate() < s.Daters[j].GetDate()
}
func main() {
// lista and listb are just examples. They really come from elsewhere
lista := []A{{"2012/08/01", "one"}, {"2012/08/03", "three"}}
listb := []B{{"2012/08/02", 2}, {"2012/08/04", 4}}
x := make([]Dater, len(lista) + len(listb))
index := 0
for i := range(lista) {
x[index] = &lista[i]
index++
}
for i := range(listb) {
x[index] = &listb[i]
index++
}
sort.Sort(ByDate{x})
for _,v := range(x) {
fmt.Printf("%#v\n", v)
}
}
That works! So the basic use of interface is fine, and I'm starting to understand
interfaces a little better - thank you!
Note: The creation of x is pretty ugly. I can't see a cleaner / more idiomatic way?
Define a interface (say Dated) with a method (say getDate() that returns Date). Then have all structs (A, B, C) implementing Dated interface. Then you can define use []Dated to hold your type values.
You might want to check package 'time' and 'sort' to simplify the implementation.
You might be able to use embedding.
You would define a struct that contains nothing but the date, then embed it in the others. That way, you only have to implement GetDate() once. You can also extend the Date struct at any time without modifying the other structs.
package main
type Dater interface {
GetDate() string
}
type Date struct {
Date string
}
func (d *Date) GetDate() string {
return d.Date
}
type A struct {
Date
Info string
}
type B struct {
Date
Info []byte
}
type C struct {
Date
Info int32
}
You can now call GetDate() on A, B, and C.

Resources