Iterate over two strings at the same time - go

I am just wondering if there is any beautiful way to iterate over two strings at the same time:
var ascii_runes = []rune(string_1)
var shifted_runes = []rune(string_2)
for i := 0; i < len(string_1); i++ {
fmt.Println(string(ascii_runes[i]) + string(shifted_runes[i]))
}

Not sure IIUC, but for example:
package main
import (
"fmt"
)
var (
ascii = []rune("string1")
shifted = []rune("STRING!")
)
func main() {
for i, v := range ascii {
fmt.Printf("%c%c\n", v, shifted[i])
}
}
Also here: http://play.golang.org/p/2ruvLFg_qe
Output:
sS
tT
rR
iI
nN
gG
1!

For example,
package main
import "fmt"
func main() {
var runes_1, runes_2 = []rune("string_1"), []rune("string_2")
for i := 0; i < len(runes_1) && i < len(runes_2); i++ {
fmt.Println(string(runes_1[i]) + string(runes_2[i]))
}
}
Output:
ss
tt
rr
ii
nn
gg
__
12

Not particularly beautiful, but an efficient way is to use strings.NewReader and its ReadRune method.
func Less(s1, s2 string) bool {
rdr1 := strings.NewReader(s1)
rdr2 := strings.NewReader(s2)
for {
rune1, _, err1 := rdr1.ReadRune()
rune2, _, err2 := rdr2.ReadRune()
if err2 == io.EOF { return false }
if err1 == io.EOF { return true }
if rune1 != rune2 { return rune1 < rune2 }
}
}

Related

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]

computing complexity of an anagram finder implementation

Given below code
package main
import (
"fmt"
"sort"
"strings"
)
func main() {
s := []string{"eat", "tea", "tan", "ate", "nat", "bat"}
result := groupAnagrams(s)
fmt.Println(result)
}
func groupAnagrams(s []string) (out [][]string) {
tmp := map[string][]string{}
for _, v := range s {
x := strings.Split(v, "")
sort.Strings(x)
anagram := strings.Join(x, "")
items, ok := tmp[anagram]
if ok {
items = append(items, v)
tmp[anagram] = items
continue
}
tmp[anagram] = []string{v}
}
var keys []string
for key := range tmp {
keys = append(keys, key)
}
sort.Strings(keys)
for _, key := range keys {
sort.Strings(tmp[key])
out = append(out, tmp[key])
}
return
}
And its tests here https://play.golang.org/p/k8F1-FAC_au
can you help figuring the complexity ?
In my understanding, and without checking thoroughly the documentation.
for _, v := range s { // o(n)
sort.Strings(keys) //o(log n)
x := strings.Split(v, "") / anagram := strings.Join(x, "") //o(n)
Are those correct ? Am i missing some ? How to compute the total ?
Do you account for total allocations when computing the complexity of a code ?
(not an answer, more like a formatted comment)
You get to choose what counts as "1 operation".
For example : in your for _, v := range s { ... } loop, I wouldn't count the processing of one single v value :
x := strings.Split(v, "")
sort.Strings(x)
anagram := strings.Join(x, "")
items, ok := tmp[anagram]
if ok {
items = append(items, v)
tmp[anagram] = items
continue
}
tmp[anagram] = []string{v}
as "1 operation". More like something that depends on len(v).
So the length of the items in your starting set will probably appear in your end formula.
this is not an answer, but, little insight as to anyone else having to deal with such things. may that help you.
I slightly revised stuff here and their, then gave a shot to a Godel-inspired scheme as described at https://stackoverflow.com/a/396077/11892070
-- main.go --
package main
import (
"fmt"
"sort"
"strings"
)
func main() {
input := []string{"tan", "nat", "⌘", "日本語", "語日本"}
freq := map[rune]int{}
for _, word := range input {
x, err := hashWord(word, freq)
fmt.Println(word, "=>", x, "err=", err)
}
}
func groupAnagramsUsingSort(s []string, tmp map[string][]string, out [][]string) [][]string {
for k := range tmp {
delete(tmp, k)
}
for i := 0; i < len(out); i++ {
out[i] = out[i][:0]
}
out = out[:0]
for _, v := range s {
x := strings.Split(v, "")
sort.Strings(x)
anagram := strings.Join(x, "")
items, ok := tmp[anagram]
if ok {
items = append(items, v)
tmp[anagram] = items
continue
}
tmp[anagram] = []string{v}
}
for key := range tmp {
out = append(out, tmp[key])
}
return out
}
func groupAnagramsUsingHash(s []string, tmp map[int][]string, out [][]string) [][]string {
for k := range tmp {
delete(tmp, k)
}
for i := 0; i < len(out); i++ {
out[i] = out[i][:0]
}
out = out[:0]
freq := map[rune]int{}
for _, v := range s {
hash, _ := hashWord(v, freq)
items, ok := tmp[hash]
if ok {
items = append(items, v)
tmp[hash] = items
continue
}
tmp[hash] = []string{v}
}
for key := range tmp {
out = append(out, tmp[key])
}
return out
}
var primes = []int{2, 41, 37, 47, 3, 67, 71, 23, 5, 101, 61, 17, 19, 13, 31, 43, 97, 29, 11, 7, 73, 83, 79, 89, 59, 53}
var ErrNonASCII = fmt.Errorf("non ascii letter detected")
func getFrequencyMap(word string, freq map[rune]int) (map[rune]int, error) {
for k := range freq {
delete(freq, k)
}
for _, r := range word {
if r-97 < 0 || int(r-97) > len(primes) {
return nil, ErrNonASCII
}
x := freq[r]
freq[r] = x + 1
}
return freq, nil
}
func hashWord(word string, freq map[rune]int) (int, error) {
var err error
freq, err = getFrequencyMap(word, freq)
if err != nil {
return -1, err
}
product := 1
for letter, r := range freq {
product = product * primes[letter-97]
for e := 1; e < r; e++ {
product = product * product
}
}
return product, nil
}
-- main_test.go --
package main
import (
"reflect"
"sort"
"testing"
)
type expectation struct {
input []string
want [][]string
}
var expectations = []expectation{
expectation{
input: []string{"eat", "tea", "tan", "ate", "nat", "bat"},
want: [][]string{
[]string{"ate", "eat", "tea"},
[]string{"bat"},
[]string{"nat", "tan"},
},
},
expectation{
input: []string{"eaft", "tea", "taen", "ate", "nate", "batf"},
want: [][]string{
[]string{"batf"},
[]string{"eaft"},
[]string{"tea", "ate"},
[]string{"taen", "nate"},
},
},
expectation{
input: []string{""},
want: [][]string{
[]string{""},
},
},
expectation{
input: []string{"a"},
want: [][]string{
[]string{"a"},
},
},
}
func TestUsingSort(t *testing.T) {
tmp := map[string][]string{}
out := [][]string{}
for _, expectation := range expectations {
out = groupAnagramsUsingSort(expectation.input, tmp, out)
if len(out) != len(expectation.want) {
t.Fatalf("unexpected output,\nwanted=%#v\ngot =%#v\n", expectation.want, out)
}
for i := 0; i < len(out); i++ {
sort.Strings(out[i])
sort.Strings(expectation.want[i])
}
sort.Slice(out, func(i int, j int) bool {
return len(out[i]) < len(out[j])
})
sort.Slice(expectation.want, func(i int, j int) bool {
return len(expectation.want[i]) < len(expectation.want[j])
})
sort.Slice(out, func(i int, j int) bool {
return (len(out[i]) > 0 &&
len(out[j]) > 0 &&
out[i][0] < out[j][0])
})
sort.Slice(expectation.want, func(i int, j int) bool {
return (len(expectation.want[i]) > 0 &&
len(expectation.want[j]) > 0 &&
expectation.want[i][0] < expectation.want[j][0])
})
for i := 0; i < len(out); i++ {
if !reflect.DeepEqual(out[i], expectation.want[i]) {
t.Fatalf("unexpected output,\nwanted=%#v\ngot =%#v\n", expectation.want, out)
}
}
}
}
func TestUsingHash(t *testing.T) {
tmp := map[int][]string{}
out := [][]string{}
for _, expectation := range expectations {
out = groupAnagramsUsingHash(expectation.input, tmp, out)
if len(out) != len(expectation.want) {
t.Fatalf("unexpected output,\nwanted=%#v\ngot =%#v\n", expectation.want, out)
}
for i := 0; i < len(out); i++ {
sort.Strings(out[i])
sort.Strings(expectation.want[i])
}
sort.Slice(out, func(i int, j int) bool {
return len(out[i]) < len(out[j])
})
sort.Slice(expectation.want, func(i int, j int) bool {
return len(expectation.want[i]) < len(expectation.want[j])
})
sort.Slice(out, func(i int, j int) bool {
return (len(out[i]) > 0 &&
len(out[j]) > 0 &&
out[i][0] < out[j][0])
})
sort.Slice(expectation.want, func(i int, j int) bool {
return (len(expectation.want[i]) > 0 &&
len(expectation.want[j]) > 0 &&
expectation.want[i][0] < expectation.want[j][0])
})
for i := 0; i < len(out); i++ {
if !reflect.DeepEqual(out[i], expectation.want[i]) {
t.Fatalf("unexpected output,\nwanted=%#v\ngot =%#v\n", expectation.want, out)
}
}
}
}
func BenchmarkUsingSort(b *testing.B) {
tmp := map[string][]string{}
out := [][]string{}
b.ResetTimer()
b.ReportAllocs()
for i := 0; i < b.N; i++ {
for _, expectation := range expectations {
out = groupAnagramsUsingSort(expectation.input, tmp, out)
_ = out
}
}
}
func BenchmarkUsingHash(b *testing.B) {
tmp := map[int][]string{}
out := [][]string{}
b.ResetTimer()
b.ReportAllocs()
for i := 0; i < b.N; i++ {
for _, expectation := range expectations {
out = groupAnagramsUsingHash(expectation.input, tmp, out)
_ = out
}
}
}
Benchmark result
$ go test -bench=. -v .
=== RUN TestUsingSort
--- PASS: TestUsingSort (0.00s)
=== RUN TestUsingHash
--- PASS: TestUsingHash (0.00s)
goos: linux
goarch: amd64
BenchmarkUsingSort
BenchmarkUsingSort-4 344438 3315 ns/op 787 B/op 29 allocs/op
BenchmarkUsingHash
BenchmarkUsingHash-4 410810 2911 ns/op 496 B/op 17 allocs/op
PASS
ok _/home/clementauger/tmp 2.408s

Can I use Go slice unpacking to streamline this permutation function?

I have written the following Go function that produces all permutations of a boolean list of any size. Playground here.
package main
import (
"fmt"
)
func permutations(m int) [][]bool {
if m == 0 {
panic("CRASH")
}
if m == 1 {
return [][]bool{{true}, {false}}
}
retVal := [][]bool{}
for _, x := range permutations(m - 1) {
slice1 := []bool{true}
slice2 := []bool{false}
for _, y := range x {
slice1 = append(slice1, y)
slice2 = append(slice2, y)
}
retVal = append(retVal, slice1)
retVal = append(retVal, slice2)
}
return retVal
}
func main() {
fmt.Println("Hello, playground")
m := permutations(3)
fmt.Println("m = ", m)
}
Can I streamline this function by using slice unpacking? If so, how?

Generate 6-digit Verification Code with Golang?

Generate 6-digit code for phone verification,
The following is a very simple approach that I have used
package main
import (
"fmt"
"math/rand"
"time"
)
var randowCodes = [...]byte{
'1', '2', '3', '4', '5', '6', '7', '8', '9', '0',
}
func main() {
var r *rand.Rand = rand.New(rand.NewSource(time.Now().UnixNano()))
for i := 0; i < 3; i++ {
var pwd []byte = make([]byte, 6)
for j := 0; j < 6; j++ {
index := r.Int() % len(randowCodes)
pwd[j] = randowCodes[index]
}
fmt.Printf("%s\n", string(pwd))
}
}
Do you have a better way to do this?
You may use "crypto/rand" package: which implements a cryptographically secure pseudorandom number generator. (try on The Go Playground):
package main
import (
"crypto/rand"
"fmt"
"io"
)
func main() {
for i := 0; i < 3; i++ {
fmt.Println(EncodeToString(6))
}
}
func EncodeToString(max int) string {
b := make([]byte, max)
n, err := io.ReadAtLeast(rand.Reader, b, max)
if n != max {
panic(err)
}
for i := 0; i < len(b); i++ {
b[i] = table[int(b[i])%len(table)]
}
return string(b)
}
var table = [...]byte{'1', '2', '3', '4', '5', '6', '7', '8', '9', '0'}
output:
640166
195174
221966
And see: How to generate a random string of a fixed length in golang?
I've forked user6169399's answer, using crypto/rand with const string and small modifications, this is the result:
import (
"crypto/rand"
)
const otpChars = "1234567890"
func GenerateOTP(length int) (string, error) {
buffer := make([]byte, length)
_, err := rand.Read(buffer)
if err != nil {
return "", err
}
otpCharsLength := len(otpChars)
for i := 0; i < length; i++ {
buffer[i] = otpChars[int(buffer[i])%otpCharsLength]
}
return string(buffer), nil
}
I think it is the easiest way:
// generate new recovery code
t := fmt.Sprint(time.Now().Nanosecond())
fmt.Println(t[:6])
output:
524339
743142
243470
function use:
func GenerateCode() string {
return fmt.Sprint(time.Now().Nanosecond())[:6]
}
output:
302663
477258
678557
You can use rand.Int() from crypto/rand to also generate randomness
import (
"crypto/rand"
)
func GenerateOTPCode(length int) (string, error) {
seed := "012345679"
byteSlice := make([]byte, length)
for i := 0; i < length; i++ {
max := big.NewInt(int64(len(seed)))
num, err := rand.Int(rand.Reader, max)
if err != nil {
return "", err
}
byteSlice[i] = seed[num.Int64()]
}
return string(byteSlice), nil
}
make use of math/rand:
func genCaptchaCode() string {
r := rand.New(rand.NewSource(time.Now().UnixNano()))
var codes [6]byte
for i := 0; i < 6; i++ {
codes[i] = uint8(48 + r.Intn(10))
}
return string(codes[:])
}
make use of crypto/rand (more security):
func genCaptchaCode() (string, error) {
codes := make([]byte, 6)
if _, err := rand.Read(codes); err != nil {
return "", err
}
for i := 0; i < 6; i++ {
codes[i] = uint8(48 + (codes[i] % 10))
}
return string(codes), nil
}
I needed a bit simpler and flat solution so I came up with this
// Since Go 1.20 rand.Seed() deprecated
rand.New(rand.NewSource(time.Now().UnixNano()))
// generates a random number in the range of [0, 900000)
// We add 100000 to the result to ensure the minimum value is 100000
r := rand.Intn(900000) + 100000
fmt.Println(r)
a side note: rand.Intn(900000) never generates 900000 the max number is 899999 so the code never generates 1,000,000
To account for the observation given by #Tom Anderson, a more appropriate answer using real uniform distribution and a simpler code would be:
func GenerateOTP(maxDigits uint32) string {
bi, err := rand.Int(
rand.Reader,
big.NewInt(int64(math.Pow(10, float64(maxDigits)))),
)
if err != nil {
panic(err)
}
return fmt.Sprintf("%0*d", maxDigits, bi)
}
go playground

How to remove repeated element in a slice?

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]

Resources