in GO, I've tried to produce the following json :
[["my",257.14,257.24],["txt", 121.11, 65.555]]
from a struct that's undergo unmarshaling - and i'm failing to do so.
Here is what I tried:
x := []MyStruct{{Zero: map[int]string{0: "str"}, One: map[int]float32{1: 5.6}, Two: map[int]float32{1: 5.88}}}
where MyStruct is :
type Timestamp struct {
Zero map[int]string `json:"0"`
One map[int]float32 `json:"1"`
Two map[int]float32 `json:"2"`
}
this produces the wrong json structure:
"myStruct":[{"0":{"0":"has"},"1":{"1":5.6},"2":{"1":5.88}}]
tried this as well
any clue in the right direction will be highly appreciated.
Maybe this is your expected. It's possible to implement custom MarshalJSON/UnmarshalJSON.
package main
import (
"encoding/json"
"errors"
"fmt"
"log"
)
type Timestamp struct {
Zero []string
One []float32
Two []float32
}
func (t *Timestamp) UnmarshalJSON(b []byte) error {
var arr [][3]interface{}
err := json.Unmarshal(b, &arr)
if err != nil {
return nil
}
t.Zero = nil
t.One = nil
t.Two = nil
for _, v := range arr {
if len(v) != 3 {
return errors.New("invalid json")
}
if s, ok := v[0].(string); ok {
t.Zero = append(t.Zero, s)
}
if f, ok := v[1].(float64); ok {
t.One = append(t.One, float32(f))
}
if f, ok := v[2].(float64); ok {
t.Two = append(t.Two, float32(f))
}
}
return nil
}
func (t *Timestamp) MarshalJSON() ([]byte, error) {
var arr [][3]interface{}
var max int
if max < len(t.Zero) {
max = len(t.Zero)
}
if max < len(t.One) {
max = len(t.One)
}
if max < len(t.Two) {
max = len(t.Two)
}
for i := 0; i < max; i++ {
var v [3]interface{}
if i < len(t.Zero) {
v[0] = t.Zero[i]
}
if i < len(t.One) {
v[1] = t.One[i]
}
if i < len(t.Two) {
v[2] = t.Two[i]
}
arr = append(arr, v)
}
return json.Marshal(arr)
}
const j = `[["my",257.14,257.24],["txt", 121.11, 65.555]]`
func main() {
var ts Timestamp
err := json.Unmarshal([]byte(j), &ts)
if err != nil {
log.Fatal(err)
}
b, err := json.Marshal(&ts)
if err != nil {
log.Fatal(err)
}
fmt.Println(string(b))
}
https://play.golang.org/p/WtVEja1JDY
The problem you are having is you're trying to unmarshal a map, and a map will correlate to a JSON object. Your desired output is a list, so you need to unmarshal an array or a slice to get a list as your values.
Try making an adapter.
Small example:
type Object struct {
Base float32
Radius float32
Height float32
X float32
Y float32
}
func (obj *Object) ToCircle() *Circle {
return &Circle{
Radius: obj.Radius,
X: obj.X,
Y: obj.Y,
}
}
func (obj *Object) ToRectangle() *Rectangle {
return &Rectangle{
Base: obj.Base,
Height: obj.Height,
X: obj.X,
Y: obj.Y,
}
}
In the example above, Object is converted to a Rectangle or a Circle using the ToRectangle() and ToCircle() adapters, respectively. In your case, you need to convert Timestamp to a []interface{}. Then you can unmarshal and you'll just get a list of whatever values are in that slice, which is your desired output in this case.
For intsance, the signature if your adapter could look like this:
func (t *Timestamp) ToFoo() []interface{} {
var ret []interface{}
// Do some stuff to take values of 't' and append to 'ret'
return ret
}
func main() {
var result []interface{}
json.Unmarshal(t.ToFoo(), &result)
// ...
}
I'll leave the implementation details for you.
Related
I am new to go, I am trying to get 3 functions to return them as follows
function 1 - To return memory usage of the system
function 2 - To return disk usage of the system
function 3 - To return CPU usage of the system
So far I am able to do this much only (PS: trying not to use any libs)
func getCPUTrack() (idle, total uint64) {
contents, err := ioutil.ReadFile("/proc/stat")
if err != nil {
return
}
lines := strings.Split(string(contents), "\n")
for _, line := range lines {
fields := strings.Fields(line)
if fields[0] == "cpu" {
numFields := len(fields)
for i := 1; i < numFields; i++ {
val, err := strconv.ParseUint(fields[i], 10, 64)
if err != nil {
fmt.Println("Error: ", i, fields[i], err)
}
total += val // tally up all the numbers to get total ticks
if i == 4 { // idle is the 5th field in the cpu line
idle = val
}
}
return
}
}
return
}
idle0, total0 := getCPUTrack()
time.Sleep(3 * time.Second)
idle1, total1 := getCPUTrack()
idleTicks := float64(idle1 - idle0)
totalTicks := float64(total1 - total0)
cpuUsage := 100 * (totalTicks - idleTicks) / totalTicks
fmt.Printf("CPU usage is %f%% [busy: %f, total: %f]\n", cpuUsage, totalTicks-idleTicks, totalTicks)
Can anyone help me with this?
Thanks
There is a pretty cool library you can use Go-osstat, or see in detail how it is implemented so you can build your own.
I've developed a client that uses this library and runs in the background sending Memory and CPU usage metrics
package main
import (
"fmt"
"os"
"time"
"github.com/mackerelio/go-osstat/cpu"
"github.com/mackerelio/go-osstat/memory"
)
const (
memoryMetric = "memory"
cpuMetric = "cpu"
retries = 10
)
type client struct {
packageName string
memoryIteration int
cpuIteration int
OSClient OSClient
}
type Client interface {
EmitMetrics()
}
type osClient struct{}
type OSClient interface {
GetMemory() (*memory.Stats, error)
GetCPU() (*cpu.Stats, error)
}
func (osc osClient) GetMemory() (*memory.Stats, error) { return memory.Get() }
func (osc osClient) GetCPU() (*cpu.Stats, error) { return cpu.Get() }
func NewClient(packageName string, memoryIteration, cpuIteration int) Client {
return newClient(packageName, memoryIteration, cpuIteration, osClient{})
}
func newClient(packageName string, memoryIteration, cpuIteration int, osclient OSClient) Client {
return &client{
packageName: packageName,
memoryIteration: memoryIteration,
cpuIteration: cpuIteration,
OSClient: osclient,
}
}
func (c *client) EmitMetrics() {
protectFromPanic := func(metric string) {
if r := recover(); r != nil {
fmt.Printf(fmt.Sprintf("Recover from fail sending %s metrics for %s", metric, c.packageName), zap.Any("recover", r))
}
}
c.sendMemoryMetrics(protectFromPanic)
c.sendCPUMetrics(protectFromPanic)
}
func (c *client) sendMemoryMetrics(f func(string)) {
count := 0
go func() {
defer func() {
f(memoryMetric)
}()
for {
memory, err := c.OSClient.GetMemory()
if err != nil {
fmt.Fprintf(os.Stderr, "%s\n", err)
count++
if count == retries {
return
}
} else {
count = 0
EmitMemoryMetrics(c.packageName, memory.Total, memory.Used, memory.Cached, memory.Free)
time.Sleep(time.Duration(c.memoryIteration) * time.Millisecond)
}
}
}()
}
func (c *client) sendCPUMetrics(f func(string)) {
go func() {
defer func() {
f(cpuMetric)
}()
for {
before, err := c.OSClient.GetCPU()
if err != nil {
fmt.Fprintf(os.Stderr, "%s\n", err)
return
}
time.Sleep(time.Duration(c.cpuIteration) * time.Millisecond)
after, err := c.OSClient.GetCPU()
if err != nil {
fmt.Fprintf(os.Stderr, "%s\n", err)
return
}
total := float64(after.Total - before.Total)
EmitCPUMetrics(c.packageName,
total,
float64(after.User-before.User)/total*100,
float64(after.System-before.System)/total*100,
float64(after.Idle-before.Idle)/total*100)
}
}()
}
How can I optimize the code below for searching an array of maps for a specific key-value (and then return the other key-values)?
type userMap struct {
JiraUsername string
CHProjectID int
CHID string
}
func main() {
var userMaps []userMap
userMaps = append(userMaps, userMap{
JiraUsername: "ted",
CHProjectID: 81,
CHID: "23jk3f32jl3323",
})
fmt.Println(GetUserInfo(userMaps, "ted"))
}
func GetUserInfo(userMaps []userMap, jiraUsername string) (CHProjectID int, CHID string) {
for _, u := range userMaps {
if u.JiraUsername == jiraUsername {
return u.CHProjectID, u.CHID
}
}
return 0, ""
}
Your code is reasonable, but it's not array of map, it's slice of struct. The efficient way would be
type userMap struct {
JiraUsername string
CHProjectID int
CHID string
}
type UsersMap map[string]userMap
func main() {
userMaps := make(UsersMap)
userMaps["ted"] = userMap{
JiraUsername: "ted",
CHProjectID: 81,
CHID: "23jk3f32jl3323",
}
fmt.Println(GetUserInfo(userMaps, "ted"))
}
func GetUserInfo(userMaps UsersMap, jiraUsername string) (CHProjectID int, CHID string) {
if u, ok := userMaps[jiraUsername]; ok {
return u.CHProjectID, u.CHID
}
return 0, ""
}
This doesn't require loop and has O(1) complexity.
I want the Struct array to have return values of the Function I defined later in the code.
In here I defined a struct "array" and info is the array of all those values in the struct, I want every element in the info array to have the respective values I mentioned, info.pos should have the value of the string I'm passing through the function PossibleMoves(), info.bitrep should have the return value from the function converttobit(), info.numrep should have the return value of toNumber(), and v1-v8 should have the values of the moves[] array, (v1=moves[0]).
My code is definitely clumsy can someone help?
package main
import ("bufio"
"fmt"
"os"
"strings")
type array struct{
pos string
bitrep int64
numrep,v1,v2,v3,v4,v5,v6,v7,v8 int8
}
func main() {
file, err := os.Open("chessin.txt")
if err != nil {
fmt.Println(err)
}
defer file.Close()
scanner := bufio.NewScanner(file)
valid := []bool{}
for scanner.Scan() {
b := strings.Split(scanner.Text(), ",")
valid = append(valid, isvalid(b))
}
fmt.Println(valid)
info :=[64][11]array {
info.pos = Possiblemoves(pos)
info.bitrep=coverttobit(num)
info.numrep=toNumber(string)
info.v0=moves[0]
info.v1=moves[1]
info.v2=moves[2]
info.v3=moves[3]
info.v4=moves[4]
info.v5=moves[5]
info.v6=moves[6]
info.v7=moves[7]
}
}
func convertingtobit( num int){
n := int64(num)
bit:=strconv.FormatInt(n, 2)
}
func isvalid(b string) bool {
if b[0]<='H' && b[0]>='A' && b[1]<='8' && b[1]>='0' {
return true
}
return false
}
func toNumber(s string) int {
if len(s) != 2 {
fmt.Println("Invalid Input",s,".")
}
num=int(s[0]-'A')*8 + int(s[1]-'0')
return num
}
func PossibleMoves(a string) {
isvalid := isvalid(a)
if isvalid == true {
var moves [8]string
moves[0]=string(a[0]+1)+string(a[1]+2)
moves[1]=string(a[0]+1)+string(a[1]-2)
moves[2]=string(a[0]-1)+string(a[1]+2)
moves[3]=string(a[0]-1)+string(a[1]-2)
moves[4]=string(a[0]+2)+string(a[1]+1)
moves[5]=string(a[0]+2)+string(a[1]-1)
moves[6]=string(a[0]-2)+string(a[1]+1)
moves[7]=string(a[0]-2)+string(a[1]-1)
fmt.Println("Possible moves are : ",moves)
var PosMoves [8] int
for i:=0;i<8;i++ {
if isvalid == true {
PosMoves[i]=toNumber(moves[i])
}
}
fmt.Println("After converting : ",PosMoves)
} else {
fmt.Println("Invalid Input")
}
}
Short Answer ( Compile: Success) :
package main
import "fmt"
type array struct {
pos string
bitrep int64
numrep, v1, v2, v3, v4, v5, v6, v7, v8 int8
}
func toNumber(s string) int8 {
if len(s) != 2 {
fmt.Println("Invalid Input", s, ".")
}
num := int8(s[0]-'A')*8 + int8(s[1]-'0')
return num
}
func PossibleMoves(out *array, a string) {
out.v1 = toNumber(string(a[0]+1) + string(a[1]+2))
}
func main() {
info := &array{
pos: "A1",
bitrep: 1,
}
PossibleMoves(info, "")
}
There are some problems:
1- in your code use := instead of = for new vars:
func toNumber(s string) int {
if len(s) != 2 {
fmt.Println("Invalid Input",s,".")
}
num=int(s[0]-'A')*8 + int(s[1]-'0')
return num
}
Like this:
func toNumber(s string) int {
if !isvalid(s) {
panic("Invalid Input" + s + ".")
}
num := int(s[0]-'A')*8 + int(s[1]-'0')
return num
}
2- your code:
func isvalid(b string) bool {
if b[0]<='H' && b[0]>='A' && b[1]<='8' && b[1]>='0' {
return true
}
return false
}
check for len(b) == 2 like this:
func isvalid(b string) bool {
if len(b) == 2 && b[0] <= 'H' && b[0] >= 'A' && b[1] <= '8' && b[1] >= '1' {
return true
}
return false
}
3- try not to copy paste:
moves[0]=string(a[0]+1)+string(a[1]+2)
moves[1]=string(a[0]+1)+string(a[1]-2)
moves[2]=string(a[0]-1)+string(a[1]+2)
moves[3]=string(a[0]-1)+string(a[1]-2)
moves[4]=string(a[0]+2)+string(a[1]+1)
moves[5]=string(a[0]+2)+string(a[1]-1)
moves[6]=string(a[0]-2)+string(a[1]+1)
moves[7]=string(a[0]-2)+string(a[1]-1)
Answering exact question:
type array struct{
pos string
bitrep int64
numrep,v1,v2,v3,v4,v5,v6,v7,v8 int8
}
func PossibleMoves(out *array, a string) {
out.v1 = tonumber(string(a[0]+1) + string(a[1]+2))
// ...
}
func main() {
// ...
info := &array{
pos: "...",
bitrep: 1234,
}
PossibleMoves(info, line)
}
But instead of this small detail, concentrate on answer by #Amd.
In Go, if I have a string variable s:
var s string = "a,b,c,d,e"
How can I convert or split or explode it into a slice or an array of strings so that it will become:
arr[0] = "a"
...
arr[4] = "e"
You should use the strings package for that.
stringSlice := strings.Split(s, ",")
http://play.golang.org/p/UKZbcuJUPP
If you want to ignore empty elements, you can use
strings#FieldsFunc:
package main
import (
"fmt"
"strings"
)
func main() {
s := ",a,,b,c,d,e,"
arr := strings.FieldsFunc(s, func(r rune) bool {
return r == ','
})
fmt.Printf("%q\n", arr) // ["a" "b" "c" "d" "e"]
}
or bufio#Scanner.Split:
package main
import (
"bufio"
"strings"
)
func comma(data []byte, eof bool) (int, []byte, error) {
if eof { return 0, nil, nil }
a := -1
for b, c := range data {
if c == ',' {
if a >= 0 {
return b+1, data[a:b], nil
}
} else if a < 0 {
a = b
}
}
return len(data), data, nil
}
func main() {
s := ",a,,b,c,d,e"
arr := bufio.NewScanner(strings.NewReader(s))
arr.Split(comma)
for arr.Scan() {
println(arr.Text())
}
}
I am trying to write a go function that will read in lines in a text file, sort them (alphabetize), and overwrite them back to the file. Right now, I am able to essentially emulate cat, but I can't seem to be able to manipulate the contents of the elements in read_line.
func sort() {
ff, _ := os.OpenFile(file, os.O_RDWR, 0666)
f := bufio.NewReader(ff)
for {
read_line, _ := f.ReadString('\n')
fmt.Print(read_line)
if read_line == "" {
break
}
}
ff.Close()
}
when i use ReadString, how can i store each line into a slice (or is there a better way to store them so i can manipulate them)? Then I would use the sort package in a manner similar to this:
sorted := sort.Strings(lines)
then, to write to the file, i am using something similar to the following, although i have not included it because i have not yet gotten "sort" to work:
io.WriteString(ff, (lines + "\n"))
Thank you in advance for any suggestions!
For example,
package main
import (
"bufio"
"fmt"
"os"
"sort"
)
func readLines(file string) (lines []string, err os.Error) {
f, err := os.Open(file)
if err != nil {
return nil, err
}
defer f.Close()
r := bufio.NewReader(f)
for {
const delim = '\n'
line, err := r.ReadString(delim)
if err == nil || len(line) > 0 {
if err != nil {
line += string(delim)
}
lines = append(lines, line)
}
if err != nil {
if err == os.EOF {
break
}
return nil, err
}
}
return lines, nil
}
func writeLines(file string, lines []string) (err os.Error) {
f, err := os.Create(file)
if err != nil {
return err
}
defer f.Close()
w := bufio.NewWriter(f)
defer w.Flush()
for _, line := range lines {
_, err := w.WriteString(line)
if err != nil {
return err
}
}
return nil
}
func main() {
file := `lines.txt`
lines, err := readLines(file)
if err != nil {
fmt.Println(err)
os.Exit(1)
}
sort.Strings(lines)
err = writeLines(file, lines)
if err != nil {
fmt.Println(err)
os.Exit(1)
}
}
This is a pretty simple way of doing it.
import (
"bytes"
"io/ioutil"
"sort"
)
// allow [][]byte to implement the sort.Interface interface
type lexicographically [][]byte
// bytes.Compare compares the byte slices lexicographically (alphabetically)
func (l lexicographically) Less(i, j int) bool { return bytes.Compare(l[i], l[j]) < 0 }
func (l lexicographically) Len() int { return len(l) }
func (l lexicographically) Swap(i, j int) { l[i], l[j] = l[j], l[i] }
func SortFile(name string) error {
content, err := ioutil.ReadFile(name)
if err != nil {
return err
}
lines := bytes.Split(content, []byte{'\n'})
sort.Sort(lexicographically(lines))
content = bytes.Join(lines, []byte{'\n'})
return ioutil.WriteFile(name, content, 0644)
}
since you are about to sort the lines, you pretty much need to read the entire file. you can either slurp the file with io/ioutil.ReadAll or you can just write a small slurp function. once you have the lines of the file, sorting them can be done with a call to sort.Strings. i'll add a perhaps overly verbose version which hopefully illustrates how it can be done. i also recomment reading this excellent explanation on how go's sort package works: Go's sort package
package main
import (
"os"
"bufio"
"fmt"
"sort"
)
// slurp file into slice of lines/strings
func slurp(f string) (lines []string, e os.Error) {
var fd *os.File
var line string
var bufRd *bufio.Reader
var keepReading bool = true
fd, e = os.Open(f)
if e != nil {
return nil, e
}
defer fd.Close()
bufRd = bufio.NewReader(fd)
for keepReading {
line, e = bufRd.ReadString('\n')
switch e {
case nil:
lines = append(lines, line)
case os.EOF:
lines = append(lines, line)
keepReading = false
default:
return lines, e
}
}
return lines, nil
}
// test stuff out..
func main() {
if len(os.Args) > 1 {
lines, e := slurp(os.Args[1])
if e != nil {
fmt.Fprintf(os.Stderr,"%s\n", e)
os.Exit(1)
}
fmt.Println("\n----- unsorted -----\n")
for _, line := range lines {
fmt.Printf("%s", line)
}
fmt.Println("\n----- sorted -----\n")
sort.Strings(lines)
for _, line := range lines {
fmt.Printf("%s", line)
}
}
}
note that the sort is in-place, so it does not return anything
Just wondering how convenient is using Unix's sort for this purpose. I know it's not possible to have this code working in many deployment scenarios, but I see it worth it to mention as an option:
package main
import (
"os"
"os/exec"
)
func main() {
file := "file.txt"
command := []string{"sort", file, "-o", file}
cmd := exec.Command(command[0], command[1:]...)
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
if err := cmd.Run(); err != nil {
panic(err)
}
}
Thoughts?