So I have a slice of letters and want to shuffle them.
I've implemented this code snippet:
rand.Shuffle(len(letters), func(i, j int) {
letters[i], letters[j] = letters[j], letters[i]
)}
When running the program it gets stuck at the first line saying: "undefined: rand.Shuffle".
in my import declaration i have imported "math/rand"
I also run this code snippet before the snippet with a problem:
rand.Seed(seed)
Where "seed" is given earlier in the code.
Also what i want is to shuffle a word but don't touch the first and last letter. Is there an easy solution to this. I have written the code like this:
rand.Shuffle(len(letters), func(i, j int) {
if i > 0 && i < (len(letters) - 1) && j > 0 && j < (len(letters) - 1){
letters[i], letters[j] = letters[j], letters[i]
}
})
Full code:
import (
"math/rand"
"strings"
"regexp"
)
func splitText(text string) []string {
re := regexp.MustCompile("[A-Za-z0-9']+|[':;?().,!\\ ]")
return re.FindAllString(text, -1)
}
func scramble(text string, seed int64) string {
token := splitText(text)
rand.Seed(seed)
if len(token) != 0{
for i := 0; i < len(token); i++{
word := token[i]
if len(word) > 3{
letters := strings.Split(word, "")
rand.Shuffle(len(letters), func(i, j int) {
if i > 0 && i < (len(letters) - 1) && j > 0 && j < (len(letters) - 1){
letters[i], letters[j] = letters[j], letters[i]
}
})
token[i] = strings.Join(letters, "")
}
}
}
returnString := strings.Join(token, "")
return returnString
}
Go 1.10 Release Notes (February 2018)
Minor changes to the library
math/rand
The new Shuffle function and corresponding Rand.Shuffle method shuffle an input sequence.
For the rand.Shuffle function, you need at least Go 1.10.
Run go version to check your version.
Related
I am trying to implement my python code in go. Here is a python code to find the inverse factorial of a large digit.
def largeInverseFactorial(n):
len_n = len(n)
i = 1
ans = 1
while True:
ans += math.log10(i)
if ans >= len_n:
return i
i += 1
Here is the go code after translating:
func largeInverseFactorial(n string) int64 {
len_n := float64(len(n))
var i float64 = 1
var ans float64 = 1
for true {
ans += math.Log10(i)
if ans >= len_n {
return int64(i)
}
i += 1
}
return 0
}
I need this go code to work with string of digits where its length can go up to 10^6. But to my surprise the go code is more than 20 times slower than its python counterpart. Can anybody tell me what am I missing in go or what's the reason behind it.
Update: The problem seems on the other side. So after using bufio.NewReader(os.Stdin).ReadString('\n') the code worked well and there is no wrong in for loop which was my original thought. Here is the code it worked:
package main
import (
"bufio"
"fmt"
"math"
"os"
"strconv"
"strings"
)
func smallInverseFactorial(value string) int64 {
var pre, ans int64
pre = 1
ans = 1
intVal, _ := strconv.ParseInt(value, 10, 64)
if intVal == 1 {
return 1
}
for ans < intVal {
ans *= pre
pre += 1
}
return pre - 1
}
func largeInverseFactorial(n string) int64 {
len_n := float64(len(n))
var i float64 = 1
var ans float64 = 1
for {
ans += math.Log10(i)
if ans >= len_n {
return int64(i)
}
i += 1
}
return 0
}
func main() {
var value string
value, _ = bufio.NewReader(os.Stdin).ReadString('\n')
value = strings.Split(value, "\n")[0]
// fmt.Scanf("%s", &value)
if len(value) < 3 {
fmt.Println(smallInverseFactorial(value))
} else {
fmt.Println(largeInverseFactorial(value))
}
}
So my question why using fmt.Scanf() is super slow when input gets larger?
I am currently trying to solve this challenge on the website CodeChef when entering input manually I get the expected answer for the problem like stated in the problem.
But when I tried to use cat in.txt | go run my_program.go the output from my program is different.
As you can see I tried to debug using fmt.Printf and it look like bufio.NewReader randomly miss the input from the pipe.
I would like to know what I am doing wrong and if there are alternative approach to read a whole line containing multiple integrers in Golang.
Thanks you for helping me !
content of in.txt :
4
3
1 2 3
3
3 2 1
3
0 0 0
3
1 3 2
normal output when entering input manually :
1 1
3 3
1 1
1 2
output with debug message when entering text using cat in.txt | go run my_program.go
debug <1 2 3
>
1 1
debug <>
1 1
debug <>
1 1
debug <>
1 1
my program :
package main
import (
"fmt"
"os"
"strings"
"bufio"
"strconv"
)
func main() {
t, n := 0, 0
fmt.Scanf("%d", &t)
for i := 0; i < t; i++ {
fmt.Scanf("%d\n", &n)
v := make([]int, n)
rd := bufio.NewReader(os.Stdin)
text, _ := rd.ReadString('\n')
fmt.Printf("debug <%s>\n", text)
arr := strings.Split(strings.TrimSuffix(text, "\n"), " ")
for k := 0; k < len(arr); k++ {
v[k], _ = strconv.Atoi(arr[k])
}
fmt.Println(calc_intersect(v))
}
}
func calc_intersect(v []int) (int, int) {
smt, lgt := 100, 0
scenario := make([]int, len(v))
for sc := 0; sc < len(v); sc++ {
infect := make([]bool, len(v))
infect[sc] = true
scenario[sc] = simulate(v, infect)
}
for i := 0; i < len(scenario); i++ {
if scenario[i] <= smt {
smt = scenario[i]
}
if scenario[i] > lgt {
lgt = scenario[i]
}
}
return smt, lgt
}
func simulate(v []int, infect []bool) int {
var nb_inf int = 1
pos := make([]int, len(v))
for time := 0; time < 25; time++ {
for p := 0; p < len(v); p++ {
pos[p] = (v[p] * time) + p
}
for a := 0; a < len(v); a++ {
check_intersect(pos, infect, &nb_inf, a)
}
}
return nb_inf
}
func check_intersect(pos []int, infect []bool, nb_inf *int, a int) {
for b := 0; b < len(pos); b++ {
if a == b {
continue
}
if pos[a] == pos[b] && (infect[a] || infect[b]) && !(infect[a] && infect[b]) {
*nb_inf += 1
infect[a], infect[b] = true, true
}
}
}
Your use of bufio.NewReader is wrong. You create a new buffered reader each time through the i loop. The reader may read ahead if input is available, and when you don't re-use the reader that buffered input is unused.
Simply move rd := bufio.NewReader(os.Stdin) outside of the loop to fix the problem.
Your code works when you read from the console via stdin because you can't type fast enough for the reader to try to buffer input.
In C you can use the function write() from the unistd.h library.
write() is faster than printf(), and allows you to write to the standard output (or a file) before a Segfault breaks your code.
When debugging, I wish to write to the standard output before my Go code panics. In general, how do I do that?
I have the following code (to find the shortest word in a string of words) which is panicking and I want to isolate where, by inserting write methods.
func FindShort(s string) int {
i := 0
j := 0
min := math.MaxInt32
for true {
for s[i] == ' ' {
i++
j++
}
for s[j] != ' ' && j < len(s) {
j++
}
if j > i && (j - i) < min {
min = j - i
}
i = j
if j == len(s) {
break
}
}
return min
}
you could use a defered function that calls the recover function, the function below will result in "Recovered panic here"
defer func() {
r := recover()
if r != nil {
fmt.Println("Recovered", r)
}
}()
panic("panic here")
Your code checks all lines if it contains a space, but it isn't checking if the line ends (end of line / end of file / line feed). There is a easier way to check what the shortest word is :
package main
import (
"fmt"
"math"
"strings"
)
func main() {
min := math.MaxInt32
shortest := math.MaxInt32
s := strings.Split("this is a test", " ")
for key, value := range s {
if len(value) < min {
min = len(value)
shortest = key
}
}
fmt.Print(s[shortest])
}
I am trying to implement fibonacci recursion in golang using n goroutines with communicating via channels.
I am returning an integer from the function, but i am actually just sending the sum of f(n-1) +f(n-2) over channel c but this is not working correctly. It prints the first two values correct, and every value after is just 1.
package main
import "fmt"
// Fibonacci in a recursive version
func fiboR(n int, c chan int ) int {
if(n == 0){
c <- 0
return 0
} else if n == 1 {
c <- 1
return 1
} else{
c <- fiboR(n-1,c) + fiboR(n-2,c)
return fiboR(n-1,c) + fiboR(n-2,c)
}
}
func main() {
for i := 0; i < 10; i++ {
procchan := make(chan int)
go fiboR(i,procchan)
fmt.Println(i,<-procchan )
}
}
Also is it possible to use channels for receiving the two recursive calls?
Your solution will try to output more than the one value you extract from the channel as you increase the value of i.
What your code will try to send to the channel for each i:
0: 0
1: 1
2: 1,0,1
3: 1,0,1,1,2
4: 1,0,1,1,2,1,0,1,3
...
Since you create a new channel for each i and then only extract one value you will always get the first value in the line above.
If you try to run it with these modifications it will output what you wanted (https://play.golang.org/p/_mn3l5x8iZ).
package main
import "fmt"
// Fibonacci in a recursive version
func fiboRchan(n int, c chan int) {
c <- fiboR(n)
}
func fiboR(n int) int {
if n == 0 {
return 0
} else if n == 1 {
return 1
} else {
return fiboR(n-1) + fiboR(n-2)
}
}
func main() {
for i := 0; i < 10; i++ {
procchan := make(chan int)
go fiboRchan(i, procchan)
fmt.Println(i, <-procchan)
}
}
Adding to #nissefors answer, the main process there is most likely a sequential one because in the for loop you would be waiting on the channel to return and then proceed to the next iteration.
A minor modification in the main function could fire all the fibonaccis at once and then in a separate for loop the channels that are corresponding to each go routine can be accessed
Playground URL: https://play.golang.org/p/7e3JnWeSp6
package main
import "fmt"
// Fibonacci in a recursive version
func fiboRchan(n int, c chan int) {
fmt.Println("PROCESSING FOR %d", n)
c <- fiboR(n)
}
func fiboR(n int) int {
if n == 0 {
return 0
} else if n == 1 {
return 1
} else {
return fiboR(n-1) + fiboR(n-2)
}
}
func main() {
var arr[10]chan int
for i := 0; i < 10; i++ {
procchan := make(chan int)
arr[i] = procchan
go fiboRchan(i, procchan)
}
// By now all the go routines are fired
// Now iterate through the channel array and read from the
// respective channel
for i:=0; i< 10; i++ {
fmt.Println(i, <-arr[i])
}
}
I have made a code to generate random numbers and delete the repeated ones like below:
package main
import (
"fmt"
"math/rand"
"time"
)
func main() {
list := [7]int{}
for i := 0; i < 7; i++ {
here:
rand.Seed(time.Now().UnixNano())
s := rand.Intn(16)
fmt.Println(s)
if s != list[0] && s != list[1] && s != list[2] && s != list[3] && s != list[4] && s != list[5] && s != list[6] {
list[i] = s
} else {
goto here
}
}
fmt.Println("list:", list)
}
I noticed that there were a lot repeated code like:
s!=list[0]&&list[1]
But when I write it to:
s!=list[0:6]
It is wrong, how can I do this properly?
Store it in map.
like that
rndmap := make(map[int]bool)
for len(rndmap) < YOUR_LEN {
rndmap[rand.Intn(YOUR_MAX_RAND)] = true
}
Result map will never store repeated indexes.
You can convert it into slice like this
rndslice := make([]int,0)
for i, _ := range rndmap {
rndslice = append(rndslice, i)
}
You can use the standard library to generate the random elements without any repetition in the first place.
package main
import (
"fmt"
"math/rand"
)
func main() {
fmt.Println(rand.Perm(16)[:7])
}
If you want a way to check a slice of ints for a value, try this function (play.golang.org):
func InSlice (arr []int, val int) (bool){
for _, v := range(arr) {
if v == val { return true; }
}
return false;
}
You can use this like below, but you won't be able to run it succesfully on play.golang.org because play.golang.org has a deterministic response to math/rand (In my case, it's 0), which will keep it from giving more than one answer, forcing this code into an infinite loop.
func main() {
list := [7]int{}
for i := 0; i < 7; i++ {
here:
rand.Seed(time.Now().UnixNano())
s := rand.Intn(16)
fmt.Println(s)
if !InSlice(list[:], s) {
list[i] = s
} else {
goto here
}
}
The following program will pick the array passed in the function findDuplicates() and returns repeated / duplicate values in another array as output. Also if there are no duplicates the function will return -1.
package main
import "fmt"
func findDuplicates(arr []int) []int {
foundMap := make(map[int]bool, 0)
respArray := []int{}
for i := 0; i < len(arr); i++ {
if foundMap[arr[i]] == true {
respArray = append(respArray, arr[i])
} else {
foundMap[arr[i]] = true
}
}
if len(respArray) == 0 {
respArray = append(respArray, -1)
}
return respArray
}
func main() {
fmt.Println(findDuplicates([]int{19, 22, 22, 100, 1, 1, 1, 22, 88}))
}
// Output [22 1 1 22]