How to provide string formatting for structs? - string

I've a struct called item
type Item struct {
Limit int
Skip int
Fields string
}
item := Item {
Limit: 3,
Skip: 5,
Fields: "Valuie",
}
how could I get the field name, value and join it into a string.
something like:
item := Item {
Limit: 3,
Skip: 5,
Fields: "Valuie",
}
to a string something like
"Limit=3&Skip=5&Fields=Valuie"
And I've try reflections to get convert interface to field value map so far. Am I going the right way? Cause I think there might have some better solutions. And thanks!
m, _ = reflections.Items(data)
for k, v := range m {
fmt.Printf("%s : %s\n", k, v)
}
I've got
Limit : %!s(int=3)
Skip : %!s(int=5)
Fields : Valuie

You can use %v instead of %s. %s will assume a string, something that can be converted to a string (i.e. byte array) or an object with a String() method.
Using %v will check the type and display it correctly.
Example of the String() method call with %s with your example: http://play.golang.org/p/bxE91IaVKj

There's no need to use reflection for this. Just write out the code for the types you have.
func (i *Item) URLValues() string {
uv := url.Values()
uv.Set("Limit", strconv.Itoa(i.Limit))
uv.Set("Skip", strconv.Itoa(i.Skip))
uv.Set("Fields", i.Fields)
return uv.Encode()
}
This code is simple, readable, and you don't need to think to write it. Unless you have a lot of types that you're going to be converting to values then I'd not even think about the magic reflection-based solution to this problem.

For any struct you can use reflection and url.Values from the net/url package:
i := Item{1, 2, "foo"}
v := url.Values{}
ri := reflect.ValueOf(i)
ri.FieldByNameFunc(func(name string) bool {
v.Set(name, fmt.Sprintf("%v", ri.FieldByName(name).Interface()))
return false
})
fmt.Println(v.Encode())
Example on play.
Of course, this code does not handle nested data structures or slices so you would need to extend
the code if you use other data structures to make it more general. However, this example should
get you started.

Take a look at go-querystring. It converts a struct into URL query parameters (your expected output).
type Item struct {
Limit int `limit:"limit"`
Skip int `url:"skip"`
Fields string `url:"fields"`
}
item := Item {
Limit: 3,
Skip: 5,
Fields: "Valuie",
}
v, _ := query.Values(item)
fmt.Print(v.Encode())
// will output: "limit=3&skip=5&fields=Valuie"

Related

How do I convert number to a specific format?

I want to know if there a way to apply custom masking/format to string and get the output
number:= 12345678
I want to format my number to a specific format.
func formatNumber(number string) string {
format:= 123-45 678
// do something here to format number
return formatedNumber
}
There are a few misconceptions in your code sample. Numbers in a computer aren't formatted, but a string representation of a number can be. Example below.
func main() {
n1 := 12345678 // type = int
fmt.Printf("type: %T, value: %d\n", n1, n1) // outputs "type: int, value: 12345678"
n2 := "12345678" // type = string
fmt.Printf("type: %T, value: %s\n", n2, n2) // outputs "type: string, value: 12345678"
}
See https://golang.org/pkg/fmt/ for where %T and %d and %s come from.
To format a number, I don't think you can get exactly what you want. A few options though:
turn an int to a string: mystring := fmt.Sprintf("%d", myint)
If you already have a string, take substrings and then add additional formatting characters in your format output.
Below gets you something like what you seem to want based on your question.
func main() {
mynumber := 12345678
mystring := fmt.Sprintf("%d", mynumber)
myformattedstring := fmt.Sprintf("%s-%s %s", mystring[:3], mystring[3:5], mystring[5:])
fmt.Println(myformattedstring)
}
Here is a playground with this code.
Use math to calculate a number for each position. Format those numbers using fmt.Sprintf:
func formatNumber(number string) string {
return fmt.Sprintf("%03d-%02d %03d",
number/100000, (number%100000)/1000,
number%1000)
}
A feature of this answered compared to others is that it correctly handles numbers less than 10000000.

How can I define a custom alphabet order for comparing and sorting strings in go?

Please read to the bottom before marking this as duplicate
I would like to be able to sort an array of strings (or a slice of structs based on one string value) alphabetically, but based on a custom alphabet or unicode letters.
Most times people advise using a collator that supports different pre-defined locales/alphabets. (See this answer for Java), but what can be done for rare languages/alphabets that are not available in these locale bundles?
The language I would like to use is not available in the list of languages supported and usable by Golangs's collate, so I need to be able to define a custom alphabet, or order of Unicode characters/runes for sorting.
Others suggest translate the strings into an english/ASCII sortable alphabet first, and then sort that. That's what's been suggested by a similar question in this solution done in Javascript or this solution in Ruby. But surely there must be a more efficient way to do this with Go.
Is it possible to create a Collator in Go that uses a custom alphabet/character set? Is that what func NewFromTable is for?
It seems that I should be able to use the Reorder function but it looks like this is not yet implemented in the language? The source code shows this:
func Reorder(s ...string) Option {
// TODO: need fractional weights to implement this.
panic("TODO: implement")
}
How can I define a custom alphabet order for comparing and sorting strings in go?
Note beforehand:
The following solution has been cleaned up and optimized, and published as a reusable library here: github.com/icza/abcsort.
Using abcsort, custom-sorting a string slice (using a custom alphabet) is as simple as:
sorter := abcsort.New("bac")
ss := []string{"abc", "bac", "cba", "CCC"}
sorter.Strings(ss)
fmt.Println(ss)
// Output: [CCC bac abc cba]
Custom-sorting a slice of structs by one of the struct field is like:
type Person struct {
Name string
Age int
}
ps := []Person{{Name: "alice", Age: 21}, {Name: "bob", Age: 12}}
sorter.Slice(ps, func(i int) string { return ps[i].Name })
fmt.Println(ps)
// Output: [{bob 12} {alice 21}]
Original answer follows:
We can implement custom sorting that uses a custom alphabet. We just need to create the appropriate less(i, j int) bool function, and the sort package will do the rest.
Question is how to create such a less() function?
Let's start by defining the custom alphabet. Convenient way is to create a string that contains the letters of the custom alphabet, enumerated (ordered) from smallest to highest. For example:
const alphabet = "bca"
Let's create a map from this alphabet, which will tell the weight or order of each letter of our custom alphabet:
var weights = map[rune]int{}
func init() {
for i, r := range alphabet {
weights[r] = i
}
}
(Note: i in the above loop is the byte index, not the rune index, but since both are monotone increasing, both will do just fine for rune weight.)
Now we can create our less() function. To have "acceptable" performance, we should avoid converting the input string values to byte or rune slices. To do that, we can call aid from the utf8.DecodeRuneInString() function which decodes the first rune of a string.
So we do the comparison rune-by-rune. If both runes are letters of the custom alphabet, we may use their weights to tell how they compare to each other. If at least one of the runes are not from our custom alphabet, we will fallback to simple numeric rune comparisons.
If 2 runes at the beginning of the 2 input strings are equal, we proceed to the next runes in each input string. We may do this my slicing the input strings: slicing them does not make a copy, it just returns a new string header that points to the data of the original strings.
All right, now let's see the implementation of this less() function:
func less(s1, s2 string) bool {
for {
switch e1, e2 := len(s1) == 0, len(s2) == 0; {
case e1 && e2:
return false // Both empty, they are equal (not less)
case !e1 && e2:
return false // s1 not empty but s2 is: s1 is greater (not less)
case e1 && !e2:
return true // s1 empty but s2 is not: s1 is less
}
r1, size1 := utf8.DecodeRuneInString(s1)
r2, size2 := utf8.DecodeRuneInString(s2)
// Check if both are custom, in which case we use custom order:
custom := false
if w1, ok1 := weights[r1]; ok1 {
if w2, ok2 := weights[r2]; ok2 {
custom = true
if w1 != w2 {
return w1 < w2
}
}
}
if !custom {
// Fallback to numeric rune comparison:
if r1 != r2 {
return r1 < r2
}
}
s1, s2 = s1[size1:], s2[size2:]
}
}
Let's see some trivial tests of this less() function:
pairs := [][2]string{
{"b", "c"},
{"c", "a"},
{"b", "a"},
{"a", "b"},
{"bca", "bac"},
}
for _, pair := range pairs {
fmt.Printf("\"%s\" < \"%s\" ? %t\n", pair[0], pair[1], less(pair[0], pair[1]))
}
Output (try it on the Go Playground):
"b" < "c" ? true
"c" < "a" ? true
"b" < "a" ? true
"a" < "b" ? false
"bca" < "bac" ? true
And now let's test this less() function in an actual sorting:
ss := []string{
"abc",
"abca",
"abcb",
"abcc",
"bca",
"cba",
"bac",
}
sort.Slice(ss, func(i int, j int) bool {
return less(ss[i], ss[j])
})
fmt.Println(ss)
Output (try it on the Go Playground):
[bca bac cba abc abcb abcc abca]
Again, if performance is important to you, you should not use sort.Slice() as that has to use reflection under the hood, but rather create your own slice type that implements sort.Interface, and in your implementation you can tell how to do it without using reflection.
This is how it could look like:
type CustStrSlice []string
func (c CustStrSlice) Len() int { return len(c) }
func (c CustStrSlice) Less(i, j int) bool { return less(c[i], c[j]) }
func (c CustStrSlice) Swap(i, j int) { c[i], c[j] = c[j], c[i] }
When you want to sort a string slice using the custom alphabet, simply convert your slice to CustStrSlice, so it can be passed directly to sort.Sort() (this type conversion does not make a copy of the slice or its elements, it just changes the type information):
ss := []string{
"abc",
"abca",
"abcb",
"abcc",
"bca",
"cba",
"bac",
}
sort.Sort(CustStrSlice(ss))
fmt.Println(ss)
Output of the above is again (try it on the Go Playground):
[bca bac cba abc abcb abcc abca]
Some things to note:
The default string comparison compares strings byte-wise. That is, if the input strings contain invalid UTF-8 sequences, the actual bytes will still be used.
Our solution is different in this regard, as we decode runes (we have to because we use a custom alphabet in which we allow runes that are not necessarily mapped to bytes 1-to-1 in UTF-8 encoding). This means if the input is not a valid UTF-8 sequence, the behavior might not be consistent with the default ordering. But if your inputs are valid UTF-8 sequences, this will do what you expect it to do.
One last note:
We've seen how a string slice could be custom-sorted. If we have a slice of structs (or a slice of pointers of structs), the sorting algorithm (the less() function) may be the same, but when comparing elements of the slice, we have to compare fields of the elements, not the struct elements themselves.
So let's say we have the following struct:
type Person struct {
Name string
Age int
}
func (p *Person) String() string { return fmt.Sprint(*p) }
(The String() method is added so we'll see the actual contents of the structs, not just their addresses...)
And let's say we want to apply our custom sorting on a slice of type []*Person, using the Name field of the Person elements. So we simply define this custom type:
type PersonSlice []*Person
func (p PersonSlice) Len() int { return len(p) }
func (p PersonSlice) Less(i, j int) bool { return less(p[i].Name, p[j].Name) }
func (p PersonSlice) Swap(i, j int) { p[i], p[j] = p[j], p[i] }
And that's all. The rest is the same, for example:
ps := []*Person{
{Name: "abc"},
{Name: "abca"},
{Name: "abcb"},
{Name: "abcc"},
{Name: "bca"},
{Name: "cba"},
{Name: "bac"},
}
sort.Sort(PersonSlice(ps))
fmt.Println(ps)
Output (try it on the Go Playground):
[{bca 0} {bac 0} {cba 0} {abc 0} {abcb 0} {abcc 0} {abca 0}]
Using table_test.go [1] as a starting point, I came up with the following. The
real work is being done by Builder.Add [2]:
package main
import (
"golang.org/x/text/collate"
"golang.org/x/text/collate/build"
)
type entry struct {
r rune
w int
}
func newCollator(ents []entry) (*collate.Collator, error) {
b := build.NewBuilder()
for _, ent := range ents {
err := b.Add([]rune{ent.r}, [][]int{{ent.w}}, nil)
if err != nil { return nil, err }
}
t, err := b.Build()
if err != nil { return nil, err }
return collate.NewFromTable(t), nil
}
Result:
package main
import "fmt"
func main() {
a := []entry{
{'a', 3}, {'b', 2}, {'c', 1},
}
c, err := newCollator(a)
if err != nil {
panic(err)
}
x := []string{"alfa", "bravo", "charlie"}
c.SortStrings(x)
fmt.Println(x) // [charlie bravo alfa]
}
https://github.com/golang/text/blob/3115f89c/collate/table_test.go
https://pkg.go.dev/golang.org/x/text/collate/build#Builder.Add

Is there any way to show the output in pretty way without 7, -48 .... etc in print statements?

The code is given below
fmt.Printf("%7s: %-48s\n", "IQN", annotations.Iqn)
fmt.Printf("%7s: %-16s\n", "Volume", args[0])
fmt.Printf("%7s: %-15s\n", "Portal", annotations.TargetPortal)
fmt.Printf("%7s: %-6s\n\n", "Size", annotations.VolSize)
No, there is not.
But you can write a utility function which automates all these, and all you need to do is pass the key-value pairs you want to pretty-print.
Let's model the key-values with this type:
type KeyValue struct {
Key string
Value interface{}
}
Note the value may be of any type, not just a string value. We'll use the default formatting when printing it. If you want a format other than the default, you can always convert it to string to your liking, and set that as the value.
The pretty-print utility function (explanation follows below):
var aligns = map[bool]string{true: "-"}
func printKeyValues(keyRight, valueRight bool, kvs ...KeyValue) {
// First convert values to string and find max key and max value lengths:
values := make([]string, len(kvs))
maxKey, maxValue := 0, 0
for i, kv := range kvs {
if length := utf8.RuneCountInString(kv.Key); length > maxKey {
maxKey = length
}
values[i] = fmt.Sprint(kv.Value)
if length := utf8.RuneCountInString(values[i]); length > maxValue {
maxValue = length
}
}
// Generate format string:
fs := fmt.Sprintf("%%%s%ds: %%%s%ds|\n",
aligns[keyRight], maxKey+1, aligns[valueRight], maxValue+1)
// And now print the key-values:
for i, kv := range kvs {
fmt.Printf(fs, kv.Key, values[i])
}
}
Testing it:
printKeyValues(false, true, []KeyValue{
{"IQN", "asdfl;kj"},
{"Volume", "asdf;lkjasdf"},
{"Portal", "asdf"},
{"Size", 12345678},
}...)
Output:
IQN: asdfl;kj |
Volume: asdf;lkjasdf |
Portal: asdf |
Size: 12345678 |
Another test:
printKeyValues(true, false, []KeyValue{
{"IQN", "asdfl;kj"},
{"Volume", "asdf;lkjasdf"},
{"Portal", "asdf"},
{"Size", 12345678},
}...)
Output:
IQN : asdfl;kj|
Volume : asdf;lkjasdf|
Portal : asdf|
Size : 12345678|
Try the examples on the Go Playground.
Explanation
The printKeyValues() first ranges over the key-value pairs, and converts values to string values, using the default formatting by calling fmt.Sprint(). Now we can find the max key length and the max value length. Note that length of a string is not len(s), as that returns the byte-length in UTF-8 encoding (which is how Go stores strings in memory). Instead to get the number of characters (or more precisely the number of runes), we used utf8.RuneCountInString().
Once we have this, we can generate the format string where the max key length and max value length is used. We will also give the possibility to control whether we want to align keys and values to the left or right, in the format string this means a - sign in case of right alignment. To get an empty string "" in case of left and a "-" in case of right, for compact code I used a simple map:
var aligns = map[bool]string{true: "-"}
Indexing this map with false gives the zero value of the value type of the map which is "", and indexing it with true will give the associated value which is "-". And since this map is always the same, I moved it outside of the function (small optimization).
To generate the format string we used fmt.Sprintf():
fs := fmt.Sprintf("%%%s%ds: %%%s%ds|\n",
aligns[keyRight], maxKey+1, aligns[valueRight], maxValue+1)
Note that % signs need to be doubled as that is special in format strings.
One final task remained: to use the generated format string to print all key-value pairs.
Thanks #icza, i found one more way, have a look on this :-)
package main
import (
"text/template"
"os"
)
func main() {
type Annotations struct {
IQN string
Volume string
Portal string
Size string
}
annotation := Annotations{
IQN: "openebs.io",
Volume: "vol",
Portal: "10.29.1.1:3260",
Size: "1G",
}
tmpl, err := template.New("test").Parse("IQN :
{{.IQN}}\nVolume : {{.Volume}}\nPortal : {{.Portal}}\nSize :
{{.Size}}")
if err != nil {
panic(err)
}
err = tmpl.Execute(os.Stdout, annotation)
if err != nil {
panic(err)
}
}
Output :
IQN : openebs.io
Volume : vol
Portal : 10.29.1.1:3260
Size : 1G
Here is the link The Go Playground

Structs in GoLang

I am just starting with GoLang, and I am looking at one of their tutorials (https://golang.org/doc/code.html).
In one of their examples, they set a variable to a struct, but I am so confused as to how they are accessing elements of the struct in the for loop below? Any chance someone can clarify? Thanks alot!
Code:
package stringutil
import "testing"
func TestReverse(t *testing.T) {
cases := []struct {
in, want string
}{
{"Hello, world", "dlrow ,olleH"},
{"Hello, 世界", "界世 ,olleH"},
{"", ""},
}
for _, c := range cases {
got := Reverse(c.in)
if got != c.want {
t.Errorf("Reverse(%q) == %q, want %q", c.in, got, c.want)
}
}
}
Below is the code with some comments to help clarify each statements role in this.
import "testing"
func TestReverse(t *testing.T) {
cases := []struct { // declaration of anonymous type
in, want string // fields on that type called in and want, both strings
}{
{"Hello, world", "dlrow ,olleH"},
{"Hello, 世界", "界世 ,olleH"},
{"", ""},
} // composite literal initilization
// note the use of := in assigning to cases, that op combines declaration and assignment into one statement
for _, c := range cases { // range over cases, ignoring the index - the underscore means to discard that return value
got := Reverse(c.in) // c is the current instance, access in with the familiar dot notation
if got != c.want { // again, access operator on c, the current instance
t.Errorf("Reverse(%q) == %q, want %q", c.in, got, c.want) // more access
}
}
}
Let me know if that helps. I can try giving more of a summary in spoken language or add more details if some of the statements don't make sense still. Also, fyi if you're not familiar range 'ranges' over a collection, returning k, v where k is the index or key and v the value.
EDIT: details on the declaration/initilization of cases
cases := []struct {
in, want string
}
This bit inside the first pair of curly braces is the definition of a struct. This is an anonymous type, a normal declaration would look like this;
type case struct {
in string
want string
}
If you had something like this then there would be a type called case in the scope of this package (not exported, if you wanted to make it 'public' so it would need to be type Case instead). Instead the examples struct is anonymous. It works the same as normal type, however as a developer, you will have no way to reference that type so you can only practically work with the collection initialized here. Internally this type is the same as any other struct with 2 unexported strings for fields. The fields are named in and want. Notice that in the assignment here cases := []struct you have [] before struct this means you're declaring a slice of this anonymous type.
This next little bit, is called static initialization. This is a syntax for initializing collections as types. Each of these nested bits like {"", ""} is the declaration and initilization of one of these anonymous structs, denoted again by the curly braces. In this case you're assigning two empty strings to in and want respectively (if you don't use names, the order is the same as in the definition). The outer pair of braces is for the slice. If your slice were of say int's or string's, then you would just have the values right there without the extra level of nesting like myInts := []int{5,6,7}.
{
{"Hello, world", "dlrow ,olleH"},
{"Hello, 世界", "界世 ,olleH"},
{"", ""},
}
Go root of what is a struct.
you declare your variables in it so then
you can use it from a function.
Example:
package main
import (
"fmt"
)
func main() {
Get()
}
func Get(){
out := new(Var)
out.name = "james"
fmt.Println(out.name)
}
type Var struct {
name string
}

Go sort a slice of runes?

I'm having trouble sorting strings by character (to check whether two strings are anagrams, I want to sort both of them, and check for equality).
I can get a []rune representation of the string s like this:
runes := make([]rune, len(s))
copy(runes, []rune(s))
And I can sort ints like this
someInts := []int{5, 2, 6, 3, 1, 4} // unsorted
sort.Ints(someInts)
But rune is just an alias for int32 so I should be able to call
sort.Ints(runes)
However, I get the error:
cannot use runes (type []rune) as type []int in function argument
So... how do I sort a slice of int32, int64, or int*?
EDIT: I did get my runes sorted, but boy, this is ugly.
type RuneSlice []rune
func (p RuneSlice) Len() int { return len(p) }
func (p RuneSlice) Less(i, j int) bool { return p[i] < p[j] }
func (p RuneSlice) Swap(i, j int) { p[i], p[j] = p[j], p[i] }
func sorted(s string) string {
runes := []rune(s)
sort.Sort(RuneSlice(runes))
return string(runes)
}
So basically if you have a slice of whatever, you'll have to wrap it in a type that implements sort.Interface. All those implementations will have the exact same method bodies (like sort.IntSlice and sort.Float64Slice). If this is really how ugly this has to be then why didn't they provide these WhateverSlice wrappers in the sort package? The lack of generics start to hurt very badly now. There must be a better way of sorting things.
Use sort.Sort(data Interface) and implement sort.Interface, see the examples on package documentation.
You cannot use rune which is int32 as int. Check the comment of int.
int is a signed integer type that is at least 32 bits in size. It is a
distinct type, however, and not an alias for, say, int32.
Note: Go 1.8 will introduce helpers for sorting slices.
See issue 16721 and commit 22a2bdf by Brad Fitzpatrick
var strings = [...]string{"", "Hello", "foo", "bar", "foo", "f00", "%*&^*&^&", "***"}
func TestSlice(t *testing.T) {
data := strings
Slice(data[:], func(i, j int) bool {
return data[i] < data[j]
})
}
Just as a point of comparison, here's what things might look like if the sort interface were slightly different. That is, rather than the interface being on the container, what would things look like if the interface were on the elements instead?
package main
import (
"fmt"
"sort"
)
type Comparable interface {
LessThan(Comparable) bool
}
type ComparableSlice []Comparable
func (c ComparableSlice) Len() int {
return len(c)
}
func (c ComparableSlice) Less(i, j int) bool {
return c[i].LessThan(c[j])
}
func (c ComparableSlice) Swap(i, j int) {
c[i], c[j] = c[j], c[i]
}
func SortComparables(elts []Comparable) {
sort.Sort(ComparableSlice(elts))
}
//////////////////////////////////////////////////////////////////////
// Let's try using this:
type ComparableRune rune
func (r1 ComparableRune) LessThan(o Comparable) bool {
return r1 < o.(ComparableRune)
}
func main() {
msg := "Hello world!"
comparables := make(ComparableSlice, len(msg))
for i, v := range msg {
comparables[i] = ComparableRune(v)
}
SortComparables(comparables)
sortedRunes := make([]rune, len(msg))
for i, v := range comparables {
sortedRunes[i] = rune(v.(ComparableRune))
}
fmt.Printf("result: %#v\n", string(sortedRunes))
}
Here, we define a Comparable interface, and we get our type ComparableRune to satisfy it. But because it's an interface, we've got to do the awkward boxing to go from rune to ComparableRune so that dynamic dispatch can kick in:
comparables := make(ComparableSlice, len(msg))
for i, v := range msg {
comparables[i] = ComparableRune(v)
}
and unboxing to get back our runes:
sortedRunes := make([]rune, len(msg))
for i, v := range comparables {
sortedRunes[i] = rune(v.(ComparableRune))
}
This approach appears to require us to know how to do typecasts to go back and forth between the interface and the dynamic type of the value. It seems like we would need to use more parts of Go---more mechanics---than the approach that uses the container as the interface.
There is, in fact a soft-generic way to do what you want.
Check out the following package:
https://github.com/BurntSushi/ty/tree/master/fun
especially the following file:
https://github.com/BurntSushi/ty/blob/master/fun/sort_test.go
Example of how it is used:
tosort := []int{10, 3, 5, 1, 15, 6}
fun.Sort(func(a, b int) bool {
return b < a
}, tosort)
There are lots of other interesting fun generic algorithms implemented through reflection in that package.
All credits go to #BurntSushi.
As of November 2020 at least, https://golang.org/pkg/sort/ offers to use a custom Less function passed as a closure. The code below has the desired effect:
package main
import (
"fmt"
"sort"
)
func main() {
s1 := "eidbaooo"
runeSlice := []rune(s1)
fmt.Println(string(runeSlice))
sort.Slice(runeSlice, func(i, j int) bool {
return runeSlice[i] < runeSlice[j]
})
fmt.Println(string(runeSlice))
}
Output:
eidbaooo
abdeiooo
This can spare you the full interface implementation.

Resources