How to combine a slice and array into map - go

I'm trying to create a morse code map in Go. How do I do this? I can also convert one slice into an array if that makes it any easier.
alphabet := []string{}
for i := 'A'; i <= 'Z'; i++ {
alphabet = append(alphabet, string(i))
}
fmt.Println(alphabet)
morseSlice := [26]string{".-","-...","-.-.","-..",".","..-.","--.","....","..",".---","-.-",".-..","--","-.","---",".--.","--.-",".-.","...","-","..-","...-",".--","-..-","-.--","--.."}
// convert to map that maps letters to morse
var morseDict map[string]string
for i := 0; i > len(morseSlice); i++ {
morseDict[alphabet[i]] = morseSlice[i]
}
fmt.Println(morseDict)
but my map is empty. What am I doing wrong?

Your code will throw an error assignment to entry in nil map. To resolve that, you need to initialise it.
elementMap := make(map[string]string) //Initialize
And your condition should be changed to less than or you can use range
for i, ele := range alphabet {
elementMap[ele] = morseSlice[i]
}
playground

Related

Accessing strings contained in slice

I am working on some coding exercises to better understand Go. A given exercise instructs me to create a program that will accept user input as follows:
The first line specifies how many strings will be provided as input on separate lines
The subsequent N lines will each be single strings
I am to output the characters corresponding to even and odd indices of each string separated by a space, and each string on it's separate line.
Example Input:
2
foo_bar
fizz_buzz
Should Output:
fobr o_a
fz_uz izbz
But in my program accessing a slice of strings returns an empty string:
package main
import (
"fmt"
)
func main() {
// read an integer describing how many strings will be input
var num_strings int
fmt.Scan(&num_strings)
// create a slice of strings to hold provided strings
strings := make([]string, num_strings)
// add provided strings to slice
for i := 0; i < num_strings; i++ {
var temp string
fmt.Scan(&temp)
strings = append(strings, temp)
}
// check that strings have been appended
fmt.Println("Strings:", strings)
// check that strings can be accessed
for i := 0; i < num_strings; i++ {
fmt.Println(i, strings[i]) // only i prints, not strings[i]
}
// loop over all strings
for i := 0; i < num_strings; i++ {
// if string index is even print the char
for index, val := range strings[i] {
if index%2 == 0 {
fmt.Print(val)
}
}
fmt.Print(" ")
// if string index is odd print the char
for index, val := range strings[i] {
if index%2 != 0 {
fmt.Print(val)
}
}
// newline for next string
fmt.Print("\n")
}
}
2
foo_bar
fizz_buzz
Strings: [ foo_bar fizz_buzz]
0
1
Because when you make your strings slice, you're creating a slice with both a capacity and length of n. So when you append to it, you're increasing the length of the slice:
Change this bit of code:
// create a slice of strings to hold provided strings
strings := make([]string, num_strings)
// add provided strings to slice
for i := 0; i < num_strings; i++ {
var temp string
fmt.Scan(&temp)
strings = append(strings, temp)
}
to either:
// create a slice of strings to hold provided strings
strings := []{}
// add provided strings to slice
for i := 0; i < num_strings; i++ {
var temp string
fmt.Scan(&temp)
strings = append(strings, temp)
}
Or
// create a slice of strings to hold provided strings
strings := make([]string, num_strings)
// add provided strings to slice
for i := 0; i < num_strings; i++ {
var temp string
fmt.Scan(&temp)
strings[i] = temp
}
And you should be good.

What does slice[0:0] do in Go?

I recently saw the following code in a Golang markdown parser:
blankLines := make([]lineStat, 0, 128)
isBlank := false
for { // process blocks separated by blank lines
_, lines, ok := reader.SkipBlankLines()
if !ok {
return
}
lineNum, _ := reader.Position()
if lines != 0 {
blankLines = blankLines[0:0]
l := len(pc.OpenedBlocks())
for i := 0; i < l; i++ {
blankLines = append(blankLines, lineStat{lineNum - 1, i, lines != 0})
}
}
I'm confused as to what blankLines = blankLines[0:0] does. Is this a way to prepend to an array?
This slicing [0:0] creates a slice that has the same backing array, but zero length. All it's really doing is "resetting" the len on the slice so that the underlying array can be re-used. It avoids the allocation that may be required if a completely new slice was created for each iteration.

How to generate alphabet slice [closed]

Closed. This question is not reproducible or was caused by typos. It is not currently accepting answers.
This question was caused by a typo or a problem that can no longer be reproduced. While similar questions may be on-topic here, this one was resolved in a way less likely to help future readers.
Closed 1 year ago.
Improve this question
I'm trying to generate an alphabet slice.
This is all I have so far
letters := []string{}
alphabet := []string{}
for i := 'A'; i <= 'Z'; i++ {
alphabet := append(letters, "a")
}
fmt.Println(alphabet)
This doesn't work. Can someone help me out?
Your program has some bugs because of which you're not getting the desired output. I've added comments to your code so that you can have a basic idea of where are you doing it incorrectly.
package main
import "fmt"
func main() {
// we don't really need the two slice
letters := []string{}
alphabet := []string{}
for i := 'A'; i <= 'Z'; i++ {
// alphabet declared but not used (compile error)
alphabet := append(letters, "a") // why hard-code "a"? wrong!
}
// print a slice of string? wrong!
// each character could be stored in byte or rune and then the slice could
// converted to string
fmt.Println(alphabet)
}
The following code might help:
package main
import "fmt"
func main() {
// Pre-allocate slice for storing 26 letters
// Note: Instead of []byte, we can use []rune as well
// But as our scope is limited to storing 'A' to 'Z' only
// byte is enought to hold each letter.
alphabet := make([]byte, 0, 26)
// Loop over 'A' to 'Z' and keep on appending
// to alphabet slice
var ch byte
for ch = 'A'; ch <= 'Z'; ch++ {
alphabet = append(alphabet, ch)
}
// Print alphabet
fmt.Println(string(alphabet))
}
With alphabet := append(letters, string(i)), you are creating a new object every time due to : and the outer one is not used.
alphabet := []string{}
for i := 'A'; i <= 'Z'; i++ {
alphabet = append(alphabet, string(i))
}
fmt.Println(alphabet)
Also, you don't need letters object as you can append on the alphabet as you go along and assign the returned object to itself.
Update: I agree with #shmsr that using string slice is an overkill if you just want to store a byte of data so you can use byte slice as:
alphabet := []byte{}
var i byte
for i = 'A'; i <= 'Z'; i++ {
alphabet = append(alphabet, i)
}
fmt.Println(string(alphabet)) // need explicit type conversion though else it prints ascii values by default
Note: You need an explicit type conversion though otherwise it prints ascii values by default.

Convert slice of struct to 2D slice of string

I want to take data from DB and write to excel
let's say I have a struct like:
type user struct {
ID int64
Name string
Age int
}
I can get a pointer to slice of user type form DB &[]user{}
but I want to convert that slice to a 2D slice of string [][]string{}
and here's my code try to do such job:
func toStrings(slice interface{}) [][]string {
switch reflect.TypeOf(slice).Elem().Kind() {
case reflect.Slice:
ret := [][]string{}
val := reflect.ValueOf(slice).Elem()
for i := 0; i < val.Len(); i++ {
tempSlice := []string{}
tempV := reflect.ValueOf(val.Index(i))
for j := 0; j < tempV.NumField(); j++ {
tempSlice = append(tempSlice, tempV.Field(j).String())
}
ret = append(ret, tempSlice)
}
return ret
}
return nil
}
But from the code above all I get is a slice like [<*reflect.rtype Value> <unsafe.Pointer Value> <reflect.flag Value>]
where I do it wrong?
my codes in golang playground
sorry, I found where I do it wrong, I got tempV wrong
func toStrings(slice interface{}) [][]string {
switch reflect.TypeOf(slice).Elem().Kind() {
case reflect.Slice:
ret := [][]string{}
val := reflect.ValueOf(slice).Elem()
for i := 0; i < val.Len(); i++ {
tempSlice := []string{}
// tempV should be:
tempV := val.Index(i)
// instead of reflect.ValueOf(val.Index(i))
for j := 0; j < tempV.NumField(); j++ {
tempSlice = append(tempSlice, tempV.Field(j).String())
}
ret = append(ret, tempSlice)
}
return ret
}
return nil
}
There are two problems in the code in the question. The first problem is the slice element is doubled wrapped by a a reflect.Value in the expression reflect.Value(val.Index(i)). Fix by removing the extra call to reflect.Value. The second problem is that the reflect.Value String method does not convert the underlying value to its string representation. Use fmt.Sprint (or one of its friends) to do that.
Try this:
func toStrings(slice interface{}) [][]string {
// Get reflect value for slice. Use Indirect to
// handle slice argument and pointer to slice
// argument.
v := reflect.Indirect(reflect.ValueOf(slice))
if v.Kind() != reflect.Slice {
return nil
}
var result [][]string
// For each element...
for i := 0; i < v.Len(); i++ {
// Get reflect value for slice element (a struct). Use
// Indirect to handle slice of struct and slice of
// pointer to struct.
e := reflect.Indirect(v.Index(i))
if e.Kind() != reflect.Struct {
return nil
}
// Convert fields to string and append.
var element []string
for i := 0; i < e.NumField(); i++ {
// Use fmt.Sprint to convert arbitrary Go value
// to a string.
element = append(element, fmt.Sprint(e.Field(i).Interface()))
}
result = append(result, element)
}
return result
}
Run it on the playground.
Maybe I have a simple way to resolve the problem, golang playground here
I used encoding/json to convert to json data, then convert it to map[string]interface{}.
func toStrings2(slice interface{}) [][]string {
jsonData, _ := json.Marshal(slice)
var out []map[string]interface{}
_ = json.Unmarshal(jsonData, &out)
var fields []string
if len(out) > 0 {
for k := range out[0] {
fields = append(fields, k)
}
}
var ret [][]string
for _, row := range out {
var r []string
for _, k := range fields {
r = append(r, fmt.Sprint(row[k]))
}
ret = append(ret, r)
}
return ret
}
Notice:
With the help of #CeriseLimón, I known that the code in this answer can't handle large values for User.ID.

how to iterate a map with its key/value with a count just like "i ++" in the "for" statement

I am using go language and I want to iterate a map with its keys and values all over a map,
at the same time, I also want to count the number of items in the map
I tried this:
for i := 0; k,v := range map; i++ { }
I just want to know if for ... range statement can work with i++ which is usual part of
for statement
As you must have discovered when you tried it, that doesn't work. You have to just spell it out:
i := 0
for k, v := range someMap {
//...
i++
}
The range clause of the for statement doesn't allow this. You have to write, for example:
var i int
for k, v := range myMap {
whatever()
i++
}
Note that if you don't mutate the map while iterating over it then
i == len(myMap)
is true afterwards.

Resources