I did this for the implementation.
csvData := make([][]string, 100)
for i := range csvData {
csvData[i] = make([]string, 100)
}
But I want to remove 100 since I don't know the actual size of the array. I want to push some string type elements into the 2d array. Basically I am reading a CSV file and want to extract its elements and store them in a 2d array. What would be a simple way to do so?
Here a working example, it creates a 10 by 10 slice.
package main
import (
"fmt"
)
func main() {
myData := "data"
var nestedSlice [][]string
nestedSize := 10
for i:=0;i<nestedSize; i++ {
jSlice := []string{}
for j:=0;j<nestedSize; j++ {
jSlice = append(jSlice, fmt.Sprintf("row:%v-col:%v-%v", i, j, myData))
}
nestedSlice = append(nestedSlice, jSlice)
}
fmt.Printf("result: %v\n", nestedSlice)
}
And here is the output showing the 10x10 slice.
result: [[row:0-col:0-data row:0-col:1-data row:0-col:2-data row:0-col:3-data row:0-col:4-data row:0-col:5-data row:0-col:6-data row:0-col:7-data row:0-col:8-data row:0-col:9-data] [row:1-col:0-data row:1-col:1-data row:1-col:2-data row:1-col:3-data row:1-col:4-data row:1-col:5-data row:1-col:6-data row:1-col:7-data row:1-col:8-data row:1-col:9-data] [row:2-col:0-data row:2-col:1-data row:2-col:2-data row:2-col:3-data row:2-col:4-data row:2-col:5-data row:2-col:6-data row:2-col:7-data row:2-col:8-data row:2-col:9-data] [row:3-col:0-data row:3-col:1-data row:3-col:2-data row:3-col:3-data row:3-col:4-data row:3-col:5-data row:3-col:6-data row:3-col:7-data row:3-col:8-data row:3-col:9-data] [row:4-col:0-data row:4-col:1-data row:4-col:2-data row:4-col:3-data row:4-col:4-data row:4-col:5-data row:4-col:6-data row:4-col:7-data row:4-col:8-data row:4-col:9-data] [row:5-col:0-data row:5-col:1-data row:5-col:2-data row:5-col:3-data row:5-col:4-data row:5-col:5-data row:5-col:6-data row:5-col:7-data row:5-col:8-data row:5-col:9-data] [row:6-col:0-data row:6-col:1-data row:6-col:2-data row:6-col:3-data row:6-col:4-data row:6-col:5-data row:6-col:6-data row:6-col:7-data row:6-col:8-data row:6-col:9-data] [row:7-col:0-data row:7-col:1-data row:7-col:2-data row:7-col:3-data row:7-col:4-data row:7-col:5-data row:7-col:6-data row:7-col:7-data row:7-col:8-data row:7-col:9-data] [row:8-col:0-data row:8-col:1-data row:8-col:2-data row:8-col:3-data row:8-col:4-data row:8-col:5-data row:8-col:6-data row:8-col:7-data row:8-col:8-data row:8-col:9-data] [row:9-col:0-data row:9-col:1-data row:9-col:2-data row:9-col:3-data row:9-col:4-data row:9-col:5-data row:9-col:6-data row:9-col:7-data row:9-col:8-data row:9-col:9-data]]
Depending on your use case there might be ways to optimise the for loop so its not n^2 time complexity but that's a different topic completely.
When creating an array or slice backed by new array you must supply a size, otherwise there is no way for the compiler to know how large to make it. But when declaring a variable to hold an array created elsewhere, just declare the var as a slice, type [][]string, which is the type of cvsData in your example.
Related
I have a []byte which I need to sort, in ascending order.
I get an object with the items and then iterate the array in order to create the object returned:
// unfortunately, for some obscure reason I can't change the data types of the caller and the object from the function call are different, although both are []byte underneath (...)
type ID []byte
// in another package:
type ByteInterface []byte
func (c *Store) GetAll() ByteInterface {
returnObj := make([]ByteInterface,0)
obj, err := GetData()
// err handling
for _, b := range obj.IDs {
returnObj = append(returnObj, ByteInterface(b))
}
return returnObj
}
So I'm asking myself if it is possible to do the append so that returnObj is sorted right away, or if I need to sort obj.ByteData upfront (or sort returnOjb afterwards).
On each iteration, do the following:
Grow the target slice (possibly reallocating it):
numElems := len(returnObj)
returnObj = append(returnObj, make([]byte, len(obj))...)
Use the standard approach for insertion to keep the destination sorted by finding a place to put each byte from the source slice, one by one:
for _, b := range obj {
i := sort.Search(numElems, func (i int) bool {
return returnObj[i] >= b
}
if i < numElems {
copy(returnObj[i+1:], returnObj[i:])
}
returnObj[i] = b
numElems++
}
(The call to copy should be optimized by copying less but this is left as an exercise for the reader.)
The following is my code where I need to Print the number of occurances of each values in an array.
package main
import "fmt"
func main(){
//Initialize an array
inputArray := []int{10,20,30,56,67,90,10,20}
printUniqueValue(inputArray)
}
func printUniqueValue( arr []int){
//Create a dictionary of values for each element
var dict map[int]int
count := 0
for _ , num := range arr {
dict[num] = count+1
}
fmt.Println(dict)
}
But I couldn't construct the dictionary as I wish like , dict[10] should have value 2.
Sample Expected Output :
dict[10] = 2
dict[20] = 2
dict[30] = 1
Error I got: panic: assignment to entry in nil map
package main
import "fmt"
func main(){
//Initialize an array
inputArray := []int{10,20,30,56,67,90,10,20}
printUniqueValue(inputArray)
}
func printUniqueValue( arr []int){
//Create a dictionary of values for each element
dict:= make(map[int]int)
for _ , num := range arr {
dict[num] = dict[num]+1
}
fmt.Println(dict)
}
This prints map[67:1 90:1 10:2 20:2 30:1 56:1]
You need to initialize dict with a non-nil map; one way would be with var dict = make(map[int]int).
Once you fix that, you will also need to deal with the logic error in dict[num] = count+1, where the count of that value is set to 1 (count is always 0) instead of one more than the previous value.
You have a couple of problems here.
You are declaring dict as a map value, but it is not assigned any value and so is nil
You are not updating the count as you are expecting
To fix the issue with the map, use the make function to assign an empty map to the dict variable. As explained above.
You are expecting:
map[10:2 20:2 30:1 56:1 67:1 90:1]
But even if the map was initialised correctly, you would get:
map[10:1 20:1 30:1 56:1 67:1 90:1]
Don't use a counter outside of the map itself. Use the existing value.
According to the Go tour maps return a zero value when queried with a non-existing key. This is a nice feature for this task, see the below code
package main
import "fmt"
func main(){
inputArray := []int{10,20,30,56,67,90,10,20}
printUniqueValue(inputArray)
}
func printUniqueValue(arr []int) {
dict := make(map[int]int)
for _ , num := range arr {
// dict[num] will return 0 if it hasn't yet been initialised
dict[num] = dict[num] + 1
}
fmt.Println(dict)
}
I'm trying to learn Go (or Golang) and can't seem to get it right. I have 2 texts files, each containing a list of words. I'm trying to count the amount of words that are present in both files.
Here is my code so far :
package main
import (
"fmt"
"log"
"net/http"
"bufio"
)
func stringInSlice(str string, list []string) bool {
for _, v := range list {
if v == str {
return true
}
}
return false
}
func main() {
// Texts URL
var list = "https://gist.githubusercontent.com/alexcesaro/c9c47c638252e21bd82c/raw/bd031237a56ae6691145b4df5617c385dffe930d/list.txt"
var url1 = "https://gist.githubusercontent.com/alexcesaro/4ebfa5a9548d053dddb2/raw/abb8525774b63f342e5173d1af89e47a7a39cd2d/file1.txt"
//Create storing arrays
var buffer [2000]string
var bufferUrl1 [40000]string
// Set a sibling counter
var sibling = 0
// Read and store text files
wordList, err := http.Get(list)
if err != nil {
log.Fatalf("Error while getting the url : %v", err)
}
defer wordList.Body.Close()
wordUrl1, err := http.Get(url1)
if err != nil {
log.Fatalf("Error while getting the url : %v", err)
}
defer wordUrl1.Body.Close()
streamList := bufio.NewScanner(wordList.Body)
streamUrl1 := bufio.NewScanner(wordUrl1.Body)
streamList.Split(bufio.ScanLines)
streamUrl1.Split(bufio.ScanLines)
var i = 0;
var j = 0;
//Fill arrays with each lines
for streamList.Scan() {
buffer[i] = streamList.Text()
i++
}
for streamUrl1.Scan() {
bufferUrl1[j] = streamUrl1.Text()
j++
}
//ERROR OCCURRING HERE :
// This code if i'm not wrong is supposed to compare through all the range of bufferUrl1 -> bufferUrl1 values with buffer values, then increment sibling and output FIND
for v := range bufferUrl1{
if stringInSlice(bufferUrl1, buffer) {
sibling++
fmt.Println("FIND")
}
}
// As a testing purpose thoses lines properly paste both array
// fmt.Println(buffer)
// fmt.Println(bufferUrl1)
}
But right now, my build doesn't even succeed. I'm only greeted with this message:
.\hello.go:69: cannot use bufferUrl1 (type [40000]string) as type string in argument to stringInSlice
.\hello.go:69: cannot use buffer (type [2000]string) as type []string in argument to stringInSlice
bufferUrl1 is an array: [4000]string. You meant to use v (each
string in bufferUrl1). But in fact, you meant to use the second
variable—the first variable is the index which is ignored in the code
below using _.
type [2000]string is different from []string. In Go, arrays and slices are not the same. Read Go Slices: usage and internals. I've changed both variable declarations to use slices with the same initial length using make.
These are changes you need to make to compile.
Declarations:
// Create storing slices
buffer := make([]string, 2000)
bufferUrl1 := make([]string, 40000)
and the loop on Line 69:
for _, s := range bufferUrl1 {
if stringInSlice(s, buffer) {
sibling++
fmt.Println("FIND")
}
}
As a side-note, consider using a map instead of a slice for buffer for more efficient lookup instead of looping through the list in stringInSlice.
https://play.golang.org/p/UcaSVwYcIw has the fix for the comments below (you won't be able to make HTTP requests from the Playground).
So, I'm trying to get used to Go! and I've come up to a problem where I try making a new data type "RandomType" which contains a slice.
package main
type RandomType struct {
RandomSlice []int
}
func main() {
r := new(RandomType)
r.RandomSlice = make([]int, 0)
append(r.RandomSlice, 5)
}
This bit of code yields an error:
append(r.RandomSlice, 5) not used
However for instance if I try with
type RandomType struct {
RandomInt int
}
func main() {
r := new(RandomType)
r.RandomInt = 5
}
this works fine.
Not sure what I'm doing wrong.
append doesn't change the slice you provide but builds a new one.
You must use the returned slice :
r.RandomSlice = append(r.RandomSlice, 5)
More details about append in Effective Go and in the Go blog.
I tried to translate the following Python code to Go
import random
list = [i for i in range(1, 25)]
random.shuffle(list)
print(list)
but found my Go version lengthy and awkward because there is no shuffle function and I had to implement interfaces and convert types.
What would be an idiomatic Go version of my code?
dystroy's answer is perfectly reasonable, but it's also possible to shuffle without allocating any additional slices.
for i := range slice {
j := rand.Intn(i + 1)
slice[i], slice[j] = slice[j], slice[i]
}
See this Wikipedia article for more details on the algorithm. rand.Perm actually uses this algorithm internally as well.
As your list is just the integers from 1 to 25, you can use Perm :
list := rand.Perm(25)
for i, _ := range list {
list[i]++
}
Note that using a permutation given by rand.Perm is an effective way to shuffle any array.
dest := make([]int, len(src))
perm := rand.Perm(len(src))
for i, v := range perm {
dest[v] = src[i]
}
Since 1.10 Go includes an official Fisher-Yates shuffle function.
Documentation: pkg/math/rand/#Shuffle
math/rand: add Shuffle
Shuffle uses the Fisher-Yates algorithm.
Since this is new API, it affords us the opportunity
to use a much faster Int31n implementation that mostly avoids division.
As a result, BenchmarkPerm30ViaShuffle is
about 30% faster than BenchmarkPerm30,
despite requiring a separate initialization loop
and using function calls to swap elements.
See also the original CL 51891
First, as commented by shelll:
Do not forget to seed the random, or you will always get the same order.
For example rand.Seed(time.Now().UnixNano())
Example:
words := strings.Fields("ink runs from the corners of my mouth")
rand.Shuffle(len(words), func(i, j int) {
words[i], words[j] = words[j], words[i]
})
fmt.Println(words)
Answer by Evan Shaw has a minor bug. If we iterate through the slice from lowest index to highest, to get a uniformly (pseudo) random shuffle, according to the same article, we must choose a random integer from interval [i,n) as opposed to [0,n+1).
That implementation will do what you need for larger inputs, but for smaller slices, it will perform a non-uniform shuffle.
To utilize rand.Intn(), we can do:
for i := len(slice) - 1; i > 0; i-- {
j := rand.Intn(i + 1)
slice[i], slice[j] = slice[j], slice[i]
}
following the same algorithm from Wikipedia article.
Maybe you can also use the following function:
func main() {
slice := []int{10, 12, 14, 16, 18, 20}
Shuffle(slice)
fmt.Println(slice)
}
func Shuffle(slice []int) {
r := rand.New(rand.NewSource(time.Now().Unix()))
for n := len(slice); n > 0; n-- {
randIndex := r.Intn(n)
slice[n-1], slice[randIndex] = slice[randIndex], slice[n-1]
}
}
When using the math/rand package, do not forget to set a source
// Random numbers are generated by a Source. Top-level functions, such as
// Float64 and Int, use a default shared Source that produces a deterministic
// sequence of values each time a program is run. Use the Seed function to
// initialize the default Source if different behavior is required for each run.
So I wrote a Shuffle function that takes this into consideration:
import (
"math/rand"
)
func Shuffle(array []interface{}, source rand.Source) {
random := rand.New(source)
for i := len(array) - 1; i > 0; i-- {
j := random.Intn(i + 1)
array[i], array[j] = array[j], array[i]
}
}
And to use it:
source := rand.NewSource(time.Now().UnixNano())
array := []interface{}{"a", "b", "c"}
Shuffle(array, source) // [c b a]
If you would like to use it, you can find it here https://github.com/shomali11/util
Raed's approach is very inflexible because of []interface{} as input. Here is more convenient version for go>=1.8:
func Shuffle(slice interface{}) {
rv := reflect.ValueOf(slice)
swap := reflect.Swapper(slice)
length := rv.Len()
for i := length - 1; i > 0; i-- {
j := rand.Intn(i + 1)
swap(i, j)
}
}
Example usage:
rand.Seed(time.Now().UnixNano()) // do it once during app initialization
s := []int{1, 2, 3, 4, 5}
Shuffle(s)
fmt.Println(s) // Example output: [4 3 2 1 5]
And also, don't forget that a little copying is better than a little dependency
Use Shuffle() from the math/rand library.
Here's an example:
package main
import (
"fmt"
"math/rand"
"strings"
)
func main() {
words := strings.Fields("ink runs from the corners of my mouth")
rand.Shuffle(len(words), func(i, j int) {
words[i], words[j] = words[j], words[i]
})
fmt.Println(words)
}
Since it comes from the math/rand library it needs to be seeded. See here for more details.