Convert string to array of single digit integers in Go - arrays

Spent several hours trying to find a solution to the 'simple' problem of converting a string of digits to an array of single digit integers in Go. Tried many different approaches, but always ran into a problem. Here is the last one tried. It builds, but gives index out of range at runtime, on the line indicated. There will probably be a few AHs that will mark me down for asking stupid questions, but I couldn't find a solution in the first 50 results of multiple Google searches. So come on dude, mark me down, you're the man. To the other 99%: Thanks for your patience and help.
package main
import (
"fmt"
"strconv"
"strings"
)
func main() {
s := "876567747896354336739443262"
var dstr []string = strings.SplitAfterN(s,"",len(s))
var dint []int
for i := 0; i < len(s); i++ {
dint[i], _ = strconv.Atoi(dstr[i]) //index out of range at runtime
fmt.Printf("dstr[%v] is: %s\n", i, dstr[i])
fmt.Printf("dint[%v] is: %v\n", i, dint[i])
}
}

Here is the answer. Morphiax showed me the error in my ways. Thanks dude, appreciated. It turns out that this is wrong: var dint []int . I should have given the size when creating the array, when not initializing it: var dint [27]int . Here's full code again:
package main
import (
"fmt"
"strconv"
"strings"
)
func main() {
s := "876567747896354336739443262"
var dstr []string = strings.SplitAfterN(s,"",len(s))
var dint [27]int
for i := 0; i < len(s); i++ {
dint[i], _ = strconv.Atoi(dstr[i])
fmt.Printf("dstr[%v] is: %s\n", i, dstr[i])
fmt.Printf("dint[%v] is: %v\n", i, dint[i])
}
}

Related

Max size of slice of string in Go

I want to input 200000 space separated strings of arbitary numbers. When taking the input using bufio.Reader it only take a few of them. Here is the code:
package main
import (
"bufio"
"fmt"
"io"
"os"
"strings"
)
func main() {
reader := bufio.NewReaderSize(os.Stdin, 1024*1024)
scoresTemp := strings.Split(readLine(reader), " ")
fmt.Println(scoresTemp)
fmt.Println("---")
fmt.Println(len(scoresTemp))
}
func readLine(reader *bufio.Reader) string {
str, _, err := reader.ReadLine()
if err == io.EOF {
return ""
}
return strings.TrimRight(string(str), "\r\n")
}
The slice length should be 200000, but it only take 410 items. If I increase the size of reader, it would be the same. What is the max size of slice of strings in Go?, How to work on it?
I believe you have an issue with your input rather than on your Go code. I've tried your code on my local machine and got this result:
$ for((i=0;i<200000;i++)) do echo -n "x "; done | go run main.go
...
---
200001
Your code doesn't iterate on the input very well. The problem isn't with slices.
Try the following code if it does what you want.
package main
import (
"bufio"
"fmt"
"os"
)
func main() {
inputScanner := bufio.NewScanner(os.Stdin)
inputScanner.Split(bufio.ScanWords)
scoresTemp := make([]string, 0, 200000)
for inputScanner.Scan() {
scoresTemp = append(scoresTemp, inputScanner.Text())
}
fmt.Println(scoresTemp)
fmt.Println("---")
fmt.Println(len(scoresTemp))
}
For the explanation:
bufio.Scanner helps "scanning" a certain input and splitting it in whichever way you like. By default it splits be new lines. Which brings us to number 2.
bufio.ScanWords is a function that splits bytes on spaces (including new-lines). This defines the behaviour of inputScanner.
Next comes the slice of strings where we store our data. It's initialized with 0 elements, and capacity of 200,000 strings. This optimizes allocation times.
PRINT !!

GoLang Print the Number of Occurances of the Values in an Array

The following is my code where I need to Print the number of occurances of each values in an array.
package main
import "fmt"
func main(){
//Initialize an array
inputArray := []int{10,20,30,56,67,90,10,20}
printUniqueValue(inputArray)
}
func printUniqueValue( arr []int){
//Create a dictionary of values for each element
var dict map[int]int
count := 0
for _ , num := range arr {
dict[num] = count+1
}
fmt.Println(dict)
}
But I couldn't construct the dictionary as I wish like , dict[10] should have value 2.
Sample Expected Output :
dict[10] = 2
dict[20] = 2
dict[30] = 1
Error I got: panic: assignment to entry in nil map
package main
import "fmt"
func main(){
//Initialize an array
inputArray := []int{10,20,30,56,67,90,10,20}
printUniqueValue(inputArray)
}
func printUniqueValue( arr []int){
//Create a dictionary of values for each element
dict:= make(map[int]int)
for _ , num := range arr {
dict[num] = dict[num]+1
}
fmt.Println(dict)
}
This prints map[67:1 90:1 10:2 20:2 30:1 56:1]
You need to initialize dict with a non-nil map; one way would be with var dict = make(map[int]int).
Once you fix that, you will also need to deal with the logic error in dict[num] = count+1, where the count of that value is set to 1 (count is always 0) instead of one more than the previous value.
You have a couple of problems here.
You are declaring dict as a map value, but it is not assigned any value and so is nil
You are not updating the count as you are expecting
To fix the issue with the map, use the make function to assign an empty map to the dict variable. As explained above.
You are expecting:
map[10:2 20:2 30:1 56:1 67:1 90:1]
But even if the map was initialised correctly, you would get:
map[10:1 20:1 30:1 56:1 67:1 90:1]
Don't use a counter outside of the map itself. Use the existing value.
According to the Go tour maps return a zero value when queried with a non-existing key. This is a nice feature for this task, see the below code
package main
import "fmt"
func main(){
inputArray := []int{10,20,30,56,67,90,10,20}
printUniqueValue(inputArray)
}
func printUniqueValue(arr []int) {
dict := make(map[int]int)
for _ , num := range arr {
// dict[num] will return 0 if it hasn't yet been initialised
dict[num] = dict[num] + 1
}
fmt.Println(dict)
}

Dump an array of interfaces in golang

I have an array of interfaces like this :
type Test struct {
Name string
}
func main() {
result := []Test{
Test{Name: "ahmad"},
Test{Name: "reza"},
}
dump(result)
}
How can I dump this array and make a string like this:
Name
ahmad
reza
I want something like this but with arrays.
Update
I don't want to dump Test interface...
I want to dump every interfaces.
package main
import (
"fmt"
"reflect"
)
type Test struct {
Name string
}
func main() {
result := []Test{
Test{Name: "ahmad"},
Test{Name: "reza"},
}
dump(result)
}
func dump(datasets interface{}) {
items := reflect.ValueOf(datasets)
if items.Kind() == reflect.Slice {
for i := 0; i < items.Len(); i++ {
item := items.Index(i)
if item.Kind() == reflect.Struct {
s := reflect.ValueOf(item)
t := reflect.TypeOf(item)
for j := 0; j < s.NumField(); j++ {
fmt.Println(t.Field(j).Name)
}
}
}
}
}
Something like this. But the result is :
typ
ptr
flag
typ
ptr
flag
How can I change output to :
Name
Name
Your example could really use more details but here is my best attempt at helping you based off what you've provided. I'm assuming the definition of dump is as follows;
func dump(items []interface{})
And that you are specifically looking to print the Name field on whatever is passed in, rather than say printing all fields on any object passed in.
func dump(items []interface{}) {
fmt.Println("Name")
for i := 0; i < len(items); i++ {
v := reflect.ValueOf(items[i])
name := v.FieldByName("Name")
fmt.Println(name.String())
}
}
Working example here; https://play.golang.org/p/zUBt6qkuok
If you instead want to print all fields that can be done with minor changes. Just add another loop inside of this where you iterate on j < v.NumField() and use v.Field(i) to get each field that's there. There are a lot of ways to structure your code at this level depending on what you want (like if you want to print FieldName1 followed by it's values then FieldName2 followed by it's values ect then your code would look quite different than if you weren't including the headers or printing each field on the current instance one after another). But these are details you'll have to worry about yourself or specify in an update to your question. Some good reading on the topic here; https://blog.golang.org/laws-of-reflection
Also the reflect packages docs are quite helpful.
I find a way !
package main
import (
"fmt"
"reflect"
)
type Test struct {
Name string
}
func main() {
result := []Test{
Test{Name: "ahmad"},
Test{Name: "reza"},
}
dump(result)
}
func dump(datasets interface{}) {
items := reflect.ValueOf(datasets)
if items.Kind() == reflect.Slice {
for i := 0; i < items.Len(); i++ {
item := items.Index(i)
if item.Kind() == reflect.Struct {
v := reflect.Indirect(item)
for j := 0; j < v.NumField(); j++ {
fmt.Println(v.Type().Field(j).Name, v.Field(j).Interface())
}
}
}
}
}
https://play.golang.org/p/JUAnVoSAwc
Thanks.

GO:array/slice to regular string

I am sort of new to golang, and also kind of new to programming. And go has been very hard for me. This is one thing that always confuses me: data types. If you run this(not on the playground) then it will spit out:
./main.go:40: cannot use recorded (type string) as type SVC in append
and if I reverse the values in the append call, it will spit out:
./main.go:40: first argument to append must be slice; have string
What I am trying to do is grab all of the stuff in the home directory, append all of the values with the modifications to an array, then put the array into a file using ioutil. All I want(as of now) is to append the values to the slice in func record. Can anybody help?
package main
import "os"
import "io/ioutil"
import "fmt"
type SVC struct {
key string
val string
}
func main() {
os.Chdir("../../../../../../..")
var data, err = ioutil.ReadDir("home")
checkerr(err)
for _, data := range data {
fmt.Println(data.Name())
}
os.Chdir("home/beanboybunny/repos/bux/go/src/bux")
}
func checkerr(err1 error) {
if err1 != nil {
fmt.Println("error")
}
}
func writer(dataname string) {
f := "var "
uname := dataname
q := " = VVC{\n"
w := " bux: 1,\n"
e := " op: true,\n"
c := "}"
b2 := f + uname + q + w + e + c
record(b2)
}
func record(recorded string) {
cache := []SVC{}
record SVC := recorded
appenda := append(cache, recorded)
}
Your type SVC struct has two private string fields. If you just want an array of strings you don't need the SVC type.
If you're just trying to build an array of strings with your specially formatted transform of the items in the home directory, here is a start showing the use of append and format strings: https://play.golang.org/p/eUKTKRxwfp
package main
import (
"fmt"
"io/ioutil"
"os"
"strings"
)
func main() {
os.Chdir("../../../../../../..")
var data, err = ioutil.ReadDir("home")
checkerr(err)
lines := []string{}
for _, data := range data {
fmt.Println(data.Name())
lines = append(lines, buildLine(data.Name()))
}
fmt.Println(strings.Join(lines, "\n"))
os.Chdir("home/beanboybunny/repos/bux/go/src/bux")
}
func checkerr(err1 error) {
if err1 != nil {
fmt.Printf("error: %v", err1)
}
}
func buildLine(dataname string) string {
return fmt.Sprintf("var %s = VVC{\n bux: 1,\n op: true,\n}", dataname)
}
You can not add meters to liters. So you can't append string type to a list of SVC records.
If you want []SVC as output (list of SVC) you need to implement a parser that transform a string to an SVC object and append it.
If you want []string as output you need to implement a serializer that transform an SVC to a string and append it.
How to do it is a separate question that is out of scope for this question.

Count similar array value

I'm trying to learn Go (or Golang) and can't seem to get it right. I have 2 texts files, each containing a list of words. I'm trying to count the amount of words that are present in both files.
Here is my code so far :
package main
import (
"fmt"
"log"
"net/http"
"bufio"
)
func stringInSlice(str string, list []string) bool {
for _, v := range list {
if v == str {
return true
}
}
return false
}
func main() {
// Texts URL
var list = "https://gist.githubusercontent.com/alexcesaro/c9c47c638252e21bd82c/raw/bd031237a56ae6691145b4df5617c385dffe930d/list.txt"
var url1 = "https://gist.githubusercontent.com/alexcesaro/4ebfa5a9548d053dddb2/raw/abb8525774b63f342e5173d1af89e47a7a39cd2d/file1.txt"
//Create storing arrays
var buffer [2000]string
var bufferUrl1 [40000]string
// Set a sibling counter
var sibling = 0
// Read and store text files
wordList, err := http.Get(list)
if err != nil {
log.Fatalf("Error while getting the url : %v", err)
}
defer wordList.Body.Close()
wordUrl1, err := http.Get(url1)
if err != nil {
log.Fatalf("Error while getting the url : %v", err)
}
defer wordUrl1.Body.Close()
streamList := bufio.NewScanner(wordList.Body)
streamUrl1 := bufio.NewScanner(wordUrl1.Body)
streamList.Split(bufio.ScanLines)
streamUrl1.Split(bufio.ScanLines)
var i = 0;
var j = 0;
//Fill arrays with each lines
for streamList.Scan() {
buffer[i] = streamList.Text()
i++
}
for streamUrl1.Scan() {
bufferUrl1[j] = streamUrl1.Text()
j++
}
//ERROR OCCURRING HERE :
// This code if i'm not wrong is supposed to compare through all the range of bufferUrl1 -> bufferUrl1 values with buffer values, then increment sibling and output FIND
for v := range bufferUrl1{
if stringInSlice(bufferUrl1, buffer) {
sibling++
fmt.Println("FIND")
}
}
// As a testing purpose thoses lines properly paste both array
// fmt.Println(buffer)
// fmt.Println(bufferUrl1)
}
But right now, my build doesn't even succeed. I'm only greeted with this message:
.\hello.go:69: cannot use bufferUrl1 (type [40000]string) as type string in argument to stringInSlice
.\hello.go:69: cannot use buffer (type [2000]string) as type []string in argument to stringInSlice
bufferUrl1 is an array: [4000]string. You meant to use v (each
string in bufferUrl1). But in fact, you meant to use the second
variable—the first variable is the index which is ignored in the code
below using _.
type [2000]string is different from []string. In Go, arrays and slices are not the same. Read Go Slices: usage and internals. I've changed both variable declarations to use slices with the same initial length using make.
These are changes you need to make to compile.
Declarations:
// Create storing slices
buffer := make([]string, 2000)
bufferUrl1 := make([]string, 40000)
and the loop on Line 69:
for _, s := range bufferUrl1 {
if stringInSlice(s, buffer) {
sibling++
fmt.Println("FIND")
}
}
As a side-note, consider using a map instead of a slice for buffer for more efficient lookup instead of looping through the list in stringInSlice.
https://play.golang.org/p/UcaSVwYcIw has the fix for the comments below (you won't be able to make HTTP requests from the Playground).

Resources