Find largest score word - go

package main
import (
"bufio"
"fmt"
"os"
"strings"
)
type word struct {
str string
score int
}
func main() {
fmt.Print("Enter a string of words: ")
reader := bufio.NewReader(os.Stdin)
str, _ := reader.ReadString('\n')
strin := strings.Trim(str, "\n")
high_word := get_word(strin)
fmt.Println(high_word)
}
func get_word(in string) []word {
rune_word := strings.Split(in, " ")
stru_sl := make([]word, len(rune_word))
for i := 0; i < len(rune_word); i++ {
stru_sl[i] = word{str: rune_word[i], score: (get_score(rune_word[i]))}
}
return stru_sl
}
func get_score(in_w string) int {
var num int
score_map := make(map[string]int)
alpha := "abcdefghijklmnopqrstuvwxyz"
alpha_run := strings.Split(alpha, "")
for i, a := range alpha_run {
score_map[a] = i + 1
}
for i := 0; i < len(in_w); i++ {
if m, ok := score_map[string(in_w[i])]; ok {
num += m
}
}
return num
}
I've got the code above that gives me a list of structs corresponding to the words you put in, and its score calculated by adding up positions of each letter in the alphabet (1-26). My next step here is to find the word with the highest score. I can do the swap method and sort the structs, but what's the smartest way to achieve this?

If you want to find only the word with the highest score of course sorting isn't necessary, you can scan linearly and update what is highest on every step.
something like that:
highestScoreWord = words[0];
for i := 1; i < len(words); i++ {
if words[i].score > highestScoreWord.score {
highestScoreWord = words[i];
}
}
return highestScoreWord;

Related

Golang code to check if first word can be formed from second word

I tried below golang code to check if first string can be formed from second string. Is there any improvement that can be done on this code?
package main
import (
"fmt"
"strings"
)
func main() {
words := []string{"hello", "ellhoo"}
result := "NO"
s := words[0]
for i := 0; i < len(words[0]); i++ {
if strings.Contains(words[1], string(s[i])) == false {
result = "NO"
break
} else {
result = "YES"
words[1] = strings.Replace(words[1],string(s[i]),"",1)
}
}
fmt.Println(result)
}
Record the count of each rune in the source string in a map. For each rune in the target string, fail if count in map is zero. Decrement count.
Here's the code:
// canmake reports whether t can constructed from the runes in s.
func canmake(t, s string) bool {
m := map[rune]int{}
for _, r := range s {
m[r]++
}
for _, r := range t {
if m[r] == 0 {
return false
}
m[r]--
}
return true
}
Here's an example showing how to use it:
func main() {
fmt.Println(canmake("hello", "ellhoo"))
fmt.Println(canmake("hello", "elhoo")) // insufficent number of l
fmt.Println(canmake("hello", "elloo")) // mising h
}

Generate random values for golange

I need a random password generator for a project, I need to make 10 of them. I found this function (random), but when I run it in a loop, it generates the same passwords. I don't know what's the problem.
func main() {
for i := 0; i < 10; i++ {
a := random()
fmt.Println(a)
}
}
func random() string {
rand.Seed(time.Now().UnixNano())
chars := []rune("abcdefghijklmnopqrstuvwxyz" + "0123456789")
length := 10
var b strings.Builder
for i := 0; i < length; i++ {
b.WriteRune(chars[rand.Intn(len(chars))])
}
str := b.String()
return str
}
Adapting your example code and refactoring it a bit:
package main
import (
"fmt"
"math/rand"
"time"
)
func main() {
rp := newRandPass(rand.New(rand.NewSource(time.Now().UnixNano())), 10, 10)
fmt.Println(rp.passwords())
}
type RandPass struct {
r *rand.Rand
num int
len int
}
func newRandPass(r *rand.Rand, num, len int) *RandPass {
return &RandPass{r, num, len}
}
func (r *RandPass) passwords() []string {
chars := []rune("abcdefghijklmnopqrstuvwxyz" + "0123456789")
passwords := make([]string, r.num)
for i := 0; i < r.num; i++ {
s := make([]rune, r.len)
for j := 0; j < r.len; j++ {
s[j] = chars[r.r.Intn(len(chars))]
}
passwords[i] = string(s)
}
return passwords
}
$ go run .
[rt97kzwjwe 5ziim05exh 40dfly93et v5tga5bwv9 avf2p2dpjx hsz4lca0jv 8r7bvvtu5l 9byf3mjq6r sdr2mpo54g cjx4mq6c0t]

cannot assign to v[i], reference to array problem?

I am trying to solve a puzzle to practice my Go. But, I am a little stuck and the error is not very helpful.
./prog.go:22:23: cannot assign to v[j]
./prog.go:22:23: cannot assign to v[wLen - 1 - j]
func SpinWords(str string) string {
ws := strings.Split(str, " ")
for i := 0; i < len(ws); i++ {
v := ws[i]
wLen := len(v)
if wLen > 4 {
for j := 0; j < wLen/2; j++ {
v[j], v[wLen-1-j] = v[wLen-1-j], v[j]
}
ws[i] = v
}
}
return strings.Join(ws, " ")
}
Almost working code here: https://play.golang.org/p/j9BYk642bFa
You can't assign to elements of v because v is a string and strings are immutable. You can convert the string to a []byte first, and then work with the elements of it, but it is not safe if your strings contain multi-byte characters.
v:=[]byte(ws[i])
Or you can convert the string to a []rune and work with it:
v:=[]rune(ws[i])
Then you can assign to elements of v, and when you're done, convert it back to a string:
str:=string(v)
If you want to performed the action then you have to convert word from string to []rune
This code works :)
package main
import (
"fmt"
"strings"
)
func main() {
result := SpinWords("Welcome to the jungle we got fun and games")
fmt.Println(result)
}
func SpinWords(str string) string {
ws := strings.Split(str, " ")
for i := 0; i < len(ws); i++ {
v := ws[i]
wLen := len(v)
if wLen > 4 {
vinrune := []rune(v)
for j := 0; j < wLen/2; j++ {
vinrune[j], vinrune[wLen-1-j] = vinrune[wLen-1-j], vinrune[j]
}
v = string(vinrune)
ws[i] = v
}
}
return strings.Join(ws, " ")
}

How to adjust the size of two-dimensional array in Go?

I have written a program that reads input lines and checks if a line begins with #.
If so, the current line and the next one will be saved in two columns in the same row in a two-dimensional array:
Go Playground
package main
import (
"bufio"
"fmt"
"strings"
)
func main() {
const input = "#FooBar1\nFooBar1\n#Foobar2\nFooBar2\n#FooBar3\nFooBar3"
var multiDimArr [3][2]string
var lineCount int
scanner := bufio.NewScanner(strings.NewReader(input))
for line := 0; scanner.Scan(); line++ {
if strings.HasPrefix(scanner.Text(), "#") {
multiDimArr[line][0] = scanner.Text()
scanner.Scan()
multiDimArr[line][1] = scanner.Text()
lineCount++
}
}
for i := 0; i < lineCount; i++ {
for j := 0; j < 2; j++ {
fmt.Printf("multiDimArr[%d][%d] = %s\n", i, j, multiDimArr[i][j])
}
}
}
Output:
multiDimArr[0][0] = #FooBar1
multiDimArr[0][1] = FooBar1
multiDimArr[1][0] = #Foobar2
multiDimArr[1][1] = FooBar2
multiDimArr[2][0] = #FooBar3
multiDimArr[2][1] = FooBar3
My problem is that I need to know the number of lines in the input when building the program, so I can adjust the size of multiDimArr.
Can I do anything to make it take any number of lines?
Try this variation:
package main
import (
"bufio"
"fmt"
"strings"
)
func main() {
const input = "#FooBar1\nFooBar1\n#Foobar2\nFooBar2\n#FooBar3\nFooBar3"
var multiDimArr [][2]string
scanner := bufio.NewScanner(strings.NewReader(input))
for scanner.Scan() {
if strings.HasPrefix(scanner.Text(), "#") {
firstLine := scanner.Text()
scanner.Scan()
secondLine := scanner.Text()
multiDimArr = append(multiDimArr, [2]string{firstLine, secondLine})
}
}
for i, row := range multiDimArr {
for j, line := range row {
fmt.Printf("multiDimArr[%d][%d] = %s\n", i, j, line)
}
}
}
Use this Slice: [][2]string{} , so you don't need to count the number of lines of input:
Try this working sample code:
package main
import "bufio"
import "fmt"
import "strings"
func main() {
const input = "#FooBar1\nFooBar1\n#Foobar2\nFooBar2\n#FooBar3\nFooBar3"
multiDimArr := [][2]string{}
for i, r := 0, bufio.NewScanner(strings.NewReader(input)); r.Scan(); i++ {
line1 := r.Text()
if !strings.HasPrefix(line1, "#") || !r.Scan() {
break
}
multiDimArr = append(multiDimArr, [2]string{line1, r.Text()})
}
fmt.Println(multiDimArr)
}
output:
[[#FooBar1 FooBar1] [#Foobar2 FooBar2] [#FooBar3 FooBar3]]
Also you may use this working sample code if you need to pre scan input to count the number of lines, using multiDimArr := make([][2]string, n) makes this slice [][2]string with length = capacity = n:
package main
import "bufio"
import "fmt"
import "strings"
func main() {
const input = "#FooBar1\nFooBar1\n#Foobar2\nFooBar2\n#FooBar3\nFooBar3"
n := 0
for r := bufio.NewScanner(strings.NewReader(input)); r.Scan() && strings.HasPrefix(r.Text(), "#") && r.Scan(); n++ {
}
multiDimArr := make([][2]string, n)
for i, r := 0, bufio.NewScanner(strings.NewReader(input)); r.Scan(); i++ {
line1 := r.Text()
if !strings.HasPrefix(line1, "#") || !r.Scan() {
break
}
multiDimArr[i] = [2]string{line1, r.Text()}
}
fmt.Println(multiDimArr)
}
Output:
[[#FooBar1 FooBar1] [#Foobar2 FooBar2] [#FooBar3 FooBar3]]
Array types:
The length is part of the array's type; it must evaluate to a
non-negative constant representable by a value of type int.
So you can't use array because its length is constant, using multiDimArr := [n][2]string{} makes compile time error: non-constant array bound n:
n := preScan(input)
//multiDimArr := [n][2]string{} // error: non-constant array bound n

Golang: find first character in a String that doesn't repeat

I'm trying to write a function that returns the finds first character in a String that doesn't repeat, so far I have this:
package main
import (
"fmt"
"strings"
)
func check(s string) string {
ss := strings.Split(s, "")
smap := map[string]int{}
for i := 0; i < len(ss); i++ {
(smap[ss[i]])++
}
for k, v := range smap {
if v == 1 {
return k
}
}
return ""
}
func main() {
fmt.Println(check("nebuchadnezzer"))
}
Unfortunately in Go when you iterate a map there's no guarantee of the order so every time I run the code I get a different value, any pointers?
Using a map and 2 loops :
play
func check(s string) string {
m := make(map[rune]uint, len(s)) //preallocate the map size
for _, r := range s {
m[r]++
}
for _, r := range s {
if m[r] == 1 {
return string(r)
}
}
return ""
}
The benfit of this is using just 2 loops vs multiple loops if you're using strings.ContainsRune, strings.IndexRune (each function will have inner loops in them).
Efficient (in time and memory) algorithms for grabbing all or the first unique byte http://play.golang.org/p/ZGFepvEXFT:
func FirstUniqueByte(s string) (b byte, ok bool) {
occur := [256]byte{}
order := make([]byte, 0, 256)
for i := 0; i < len(s); i++ {
b = s[i]
switch occur[b] {
case 0:
occur[b] = 1
order = append(order, b)
case 1:
occur[b] = 2
}
}
for _, b = range order {
if occur[b] == 1 {
return b, true
}
}
return 0, false
}
As a bonus, the above function should never generate any garbage. Note that I changed your function signature to be a more idiomatic way to express what you're describing. If you need a func(string) string signature anyway, then the point is moot.
That can certainly be optimized, but one solution (which isn't using map) would be:
(playground example)
func check(s string) string {
unique := ""
for pos, c := range s {
if strings.ContainsRune(unique, c) {
unique = strings.Replace(unique, string(c), "", -1)
} else if strings.IndexRune(s, c) == pos {
unique = unique + string(c)
}
}
fmt.Println("All unique characters found: ", unique)
if len(unique) > 0 {
_, size := utf8.DecodeRuneInString(unique)
return unique[:size]
}
return ""
}
This is after the question "Find the first un-repeated character in a string"
krait suggested below that the function should:
return a string containing the first full rune, not just the first byte of the utf8 encoding of the first rune.

Resources