Ranging over a slice - go

my problem is that Im only allowed to use the command PrintRune, i must range over a string and print one by one the characters of any string
package piscine
import "github.com/01-edu/z01"
func PrintStr(s string) {
slice := []string{
s,
}
for x, word := range slice {
z01.PrintRune(rune(word[x]))
}
}
here's my code, this only prints the first character of the string, how can i make the slice continue until the end of the given string please ?

Here is the code snippets:
package piscine
import "github.com/01-edu/z01"
func PrintStr(s string) {
slice := []string{
s,
}
for _, word := range slice {
for _, r := range word {
z01.PrintRune(rune(r))
}
}
}

Related

How to convert strings to lower case in GO?

I am new to the language GO and working on an assignment where i should write a code that return the word frequencies of the text. However I know that the words 'Hello', 'HELLO' and 'hello' are all counted as 'hello', so I need to convert all strings to lower case.
I know that I should use strings.ToLower(), however I dont know where I should Included that in the class. Can someone please help me?
package main
import (
"fmt"
"io/ioutil"
"log"
"strings"
"time"
)
const DataFile = "loremipsum.txt"
// Return the word frequencies of the text argument.
func WordCount(text string) map[string]int {
fregs := make(map[string]int)
words := strings.Fields(text)
for _, word := range words {
fregs[word] += 1
}
return fregs
}
// Benchmark how long it takes to count word frequencies in text numRuns times.
//
// Return the total time elapsed.
func benchmark(text string, numRuns int) int64 {
start := time.Now()
for i := 0; i < numRuns; i++ {
WordCount(text)
}
runtimeMillis := time.Since(start).Nanoseconds() / 1e6
return runtimeMillis
}
// Print the results of a benchmark
func printResults(runtimeMillis int64, numRuns int) {
fmt.Printf("amount of runs: %d\n", numRuns)
fmt.Printf("total time: %d ms\n", runtimeMillis)
average := float64(runtimeMillis) / float64(numRuns)
fmt.Printf("average time/run: %.2f ms\n", average)
}
func main() {
// read in DataFile as a string called data
data, err:= ioutil.ReadFile("loremipsum.txt")
if err != nil {
log.Fatal(err)
}
// Convert []byte to string and print to screen
text := string(data)
fmt.Println(text)
fmt.Printf("%#v",WordCount(string(data)))
numRuns := 100
runtimeMillis := benchmark(string(data), numRuns)
printResults(runtimeMillis, numRuns)
}
You should convert words to lowercase when you are using them as map key
for _, word := range words {
fregs[strings.ToLower(word)] += 1
}
I get [a:822 a.:110 I want all a in the same. How do i a change the code so that a and a. is the same? – hello123
You need to carefully define a word. For example, a string of consecutive letters and numbers converted to lowercase.
func WordCount(s string) map[string]int {
wordFunc := func(r rune) bool {
return !unicode.IsLetter(r) && !unicode.IsNumber(r)
}
counts := make(map[string]int)
for _, word := range strings.FieldsFunc(s, wordFunc) {
counts[strings.ToLower(word)]++
}
return counts
}
to remove all non-word characters you could use a regular expression:
package main
import (
"bufio"
"fmt"
"log"
"regexp"
"strings"
)
func main() {
str1 := "This is some text! I want to count each word. Is it cool?"
re, err := regexp.Compile(`[^\w]`)
if err != nil {
log.Fatal(err)
}
str1 = re.ReplaceAllString(str1, " ")
scanner := bufio.NewScanner(strings.NewReader(str1))
scanner.Split(bufio.ScanWords)
for scanner.Scan() {
fmt.Println(strings.ToLower(scanner.Text()))
}
}
See strings.EqualFold.
Here is an example.

Trying to reverse strings but there are spaces after reversing the string

I was trying to write a stringReverse function which reverses the given string:
func reverseString(s string) []rune
well, i did succeed but the problem is there are spaces after reversing it.
Input: "Hello, 世界"
Output: [界 世 , o l l e H]
code of function :
func reverseString(s string) []rune {
// sir: string in rune
sir := []rune(s)
for i, _ := range sir {
sir[i], sir[len(sir)-i-1] = sir[len(sir)-i-1], sir[i]
if i >= len(sir)-i-1 {
return sir
}
}
return sir
}
i did not do any error implementation since i am new to go.
Thanks for your help.
To reverse strings,you can declare an empty string and then start appending the characters from the end, one by one.Here is a sample code for the same logic:
package main
import "fmt"
func reverse(str string) (result string) {
for _, v := range str {
result = string(v) + result
}
return
}
func main() {
runeStr := "Hello, 世界"
fmt.Println(runeStr)
runeRev := reverse(runeStr)
fmt.Println(runeRev)
}
Output:
Hello, 世界
界世 ,olleH
try to
func reverseString(s string) []rune {
// sir: string in rune
sir := []rune(s)
for i, _ := range sir {
sir[i], sir[len(sir)-i-1] = sir[len(sir)-i-1], sir[i]
if i+1 >= len(sir)/2 {
return sir
}
}
return sir
}

How to make a slice from a mapset.Set?

I'm reading Donovan's "The Go Programming Language" book and trying to implement an exercise which prints duplicate lines from several files and the files in which they occur:
package main
import (
"fmt"
"io/ioutil"
"os"
"strings"
mapset "github.com/deckarep/golang-set"
)
func main() {
counts := make(map[string]int)
occurrences := make(map[string]mapset.Set)
for _, filename := range os.Args[1:] {
data, err := ioutil.ReadFile(filename)
if err != nil {
fmt.Fprintf(os.Stderr, "dup3: %v\n", err)
continue
}
for _, line := range strings.Split(string(data), "\n") {
counts[line]++
occurrences[line].Add(filename)
}
}
for line, n := range counts {
if n > 1 {
fmt.Printf("%d\t%s\t%s\n", n, line, strings.Join(occurrences[line], ", "))
}
}
}
To accomplish the exercise, I've used the https://godoc.org/github.com/deckarep/golang-set package. However, I'm not sure how to print out the elements of the set joined by a ", ". With this code, I get a
./hello.go:23:30: first argument to append must be slice; have interface { Add(interface {}) bool; Cardinality() int; CartesianProduct(mapset.Set) mapset.Set; Clear(); Clone() mapset.Set; Contains(...interface {}) bool; Difference(mapset.Set) mapset.Set; Each(func(interface {}) bool); Equal(mapset.Set) bool; Intersect(mapset.Set) mapset.Set; IsProperSubset(mapset.Set) bool; IsProperSuperset(mapset.Set) bool; IsSubset(mapset.Set) bool; IsSuperset(mapset.Set) bool; Iter() <-chan interface {}; Iterator() *mapset.Iterator; Pop() interface {}; PowerSet() mapset.Set; Remove(interface {}); String() string; SymmetricDifference(mapset.Set) mapset.Set; ToSlice() []interface {}; Union(mapset.Set) mapset.Set }
./hello.go:28:64: cannot use occurrences[line] (type mapset.Set) as type []string in argument to strings.Join
I wasn't able to easily find out how to convert the Set to a slice though. Any idea how I might accomplish this?
The XY problem is asking about your attempted solution rather than your actual problem: The XY Problem.
The Go Programming Language by Alan A. A. Donovan and Brian W. Kernighan, Exercise 1.4 is designed to use Go maps.
For example,
// Modify dup3 to print the names of all files in which each duplicated line occurs.
package main
import (
"fmt"
"io/ioutil"
"os"
"strings"
)
func main() {
// counts = [line][file]count
counts := make(map[string]map[string]int)
for _, filename := range os.Args[1:] {
data, err := ioutil.ReadFile(filename)
if err != nil {
fmt.Fprintf(os.Stderr, "Exercise 1.4: %v\n", err)
continue
}
for _, line := range strings.Split(string(data), "\n") {
files := counts[line]
if files == nil {
files = make(map[string]int)
counts[line] = files
}
files[filename]++
}
}
for line, files := range counts {
n := 0
for _, count := range files {
n += count
}
if n > 1 {
fmt.Printf("%d\t%s\n", n, line)
for name := range files {
fmt.Printf("%s\n", name)
}
}
}
}

How to pass a create a slice of a 2d array

I am having trouble to pass a slice of a 2d array of strings inside a func : this is my playground
Golang playground
package main
import (
"fmt"
)
func main() {
board := [2][3]string{
{"O", "_", "O"},
{"X", "O", "_"},
}
printBoard(board[:][:])
}
func printBoard(board [][]string){
for _, line := range board {
for _, cell := range line {
fmt.Printf("%s", cell)
}
fmt.Println()
}
}
It says cannot use board[:][:] (type [][3]string) as type [][]string in argument to printBoard
I did not manage to correct it printBoard(board[:][:]).
I tried by removing one/both semicolons inside the call, but did not work either. I do not want to specify any length if possible
In go, arrays have fixed sizes contrary to slices, so here you need to specify the size of your array as the argument, otherwise you will get this error:
prog.go:13:12: cannot use board (type [2][3]string) as type [][]string in argument to printBoard
Here it is fixed:
package main
import (
"fmt"
)
func main() {
board := [2][3]string{
{"O", "_", "O"},
{"X", "O", "_"},
}
printBoard(board)
}
func printBoard(board [2][3]string){
for _, line := range board {
for _, cell := range line {
fmt.Printf("%s", cell)
}
fmt.Println()
}
}
Outputs
O_O
XO_
I'm not sure why you decided to use arrays but in go, whenever possible you should prefer using slices instead of arrays, as they're more flexible, cleaner and less bug-prone.
Here is the implementation with slices instead:
package main
import (
"fmt"
)
func main() {
board := [][]string{
{"O", "_", "O"},
{"X", "O", "_"},
}
printBoard(board)
}
func printBoard(board [][]string){
for _, line := range board {
for _, cell := range line {
fmt.Printf("%s", cell)
}
fmt.Println()
}
}
Note that you don't need to change your logic, and you don't need to specify sizes anywhere anymore.

How to convert string from interface to []string in golang?

I'm parsing a JSON object which contains an array of strings :
var ii interface{}
json := "{\"aString\": [\"aaa_111\", \"bbb_222\"], \"whatever\":\"ccc\"}"
err := json.Unmarshal([]byte(json), &ii)
if err != nil {
log.Fatal(err)
}
data := ii.(map[string]interface{})
fmt.Println(data["aString"]) // outputs: ["aaa_111" "bbb_222"]
I tried to convert data["aString"] to []string to be able to loop over it, but it fails :
test := []string(data["aString"]).([]string)
fmt.Println(test) // panic -> interface conversion:
// interface is string, not []string
How can I convert data["aString"] ?
edit:
I didn't express myself properly. If I print data, I have such map :
map[aString:["BBB-222","AAA-111"] whatever:ccc]
I want to loop over aString (to manipule each array entry). But I can't find how, because aString is type interface {} :
for i, v := range aString { // <-- fails
// ...
fmt.Println(i, v)
}
That's why I want to convert aString. I don't want to convert a string which looks like an array to an array.
I recommend you move away from this implementation in general. Your json may vary but you can easily use objects and avoid all this type unsafe nonsense.
Anyway, that conversion doesn't work because the types inside the slice are not string, they're also interface{}. You have to iterate the collection then do a type assertion on each item like so:
aInterface := data["aString"].([]interface{})
aString := make([]string, len(aInterface))
for i, v := range aInterface {
aString[i] = v.(string)
}
Is it what you need?
package main
import (
"fmt"
"encoding/json"
)
func main() {
js := "{\"aString\": [\"aaa_111\", \"bbb_222\"], \"whatever\":\"ccc\"}"
a := make(map[string]interface{})
json.Unmarshal([]byte(js), &a)
for _, v := range a["aString"].([]interface{}) {
str := v.(string)
fmt.Println(str)
}
}
Check on Go Playground
For another approach, you can use a struct instead:
package main
import (
"encoding/json"
"fmt"
)
func main() {
s := []byte(`{"aString": ["aaa_111", "bbb_222"], "whatever":"ccc"}`)
var t struct {
Astring []string
Whatever string
}
json.Unmarshal(s, &t)
fmt.Printf("%+v\n", t) // {Astring:[aaa_111 bbb_222] Whatever:ccc}
}

Resources