slice Archives - Welcome To Golang By Example https://vikasboss.github.io/tag/slice/ Thu, 14 Jul 2022 16:47:18 +0000 en-US hourly 1 https://wordpress.org/?v=6.8.1 https://i0.wp.com/golangbyexamples.com/wp-content/uploads/2021/05/cropped-go_border-1.png?fit=32%2C32&ssl=1 slice Archives - Welcome To Golang By Example https://vikasboss.github.io/tag/slice/ 32 32 159787465 Slice in Go (Golang) https://vikasboss.github.io/slice-in-golang/ https://vikasboss.github.io/slice-in-golang/#comments Mon, 18 May 2020 16:52:20 +0000 https://vikasboss.github.io/?p=2181 This is the  chapter 18 of the golang comprehensive tutorial series. Refer to this link for other chapters of the series – Golang Comprehensive Tutorial Series Next Tutorial – MapsPrevious Tutorial – Array Now let’s check...

The post Slice in Go (Golang) appeared first on Welcome To Golang By Example.

]]>
This is the  chapter 18 of the golang comprehensive tutorial series. Refer to this link for other chapters of the series – Golang Comprehensive Tutorial Series

Next Tutorial – Maps
Previous Tutorial – Array

Now let’s check out the current tutorial. Below is the table of contents for current tutorial.

Overview

The size of the array being part of it limits the expressiveness and power of array in go. This is where slice comes into the picture. Slice is more powerful and convenient to use than an array.  Slice, in fact, is more analogous to arrays in another programming language.

A slice points to an underlying array and is internally represented by a slice header.  Unlike array, the size of a slice is flexible and can be changed.

Internal representation of a slice

Internally a slice is represented by three things.

  • Pointer to the underlying array
  • Current length of the underlying array
  • Total Capacity which is the maximum capacity to which the underlying array can expand.

Above internal representation is described by SliceHeader struct which looks like this:

type SliceHeader struct {
        Pointer uintptr
        Len  int
        Cap  int
}

The Pointer field in the slice header is a pointer to the underlying array.  Len is the current length of the slice and Cap is the capacity of the slice. Similar to array a slice index starts from zero till length_of_slice-1. So a slice of 3 lengths and 5 capacity will look like below

Creating a slice

There are four ways of creating a slice

  • Using the []<type>{} format
  • Creating a slice from another slice or array
  • Using make
  • Using new

Let’s look at each of above method one by one.

Using the []<type>{} format

The most common way of declaring a slice is this

s := []int

It declares an empty of slice of 0 length and 0 capacity. We can also initialise the slice during declaration.

s := []int{1,2}

It declares a slice of integers of length 2 and also the capacity of 2. The capacity will be equal to the actual slice elements specified. We also have two library functions provided by go which can be used to know the length and capacity of a slice.

  • len() function – for  length of the slice
  • cap() function – for capacity of the slice

Let’s see a small program which shows the above points

package main

import "fmt"

func main() {
    sample := []int{}
    fmt.Println(len(sample))
    fmt.Println(cap(sample))
    fmt.Println(sample)

    letters := []string{"a", "b", "c"}
    fmt.Println(len(letters))
    fmt.Println(cap(letters))
    fmt.Println(letters)
}

Output

0
0
[]

3
3
[a b c]

When the actual elements are not specified, then both length and capacity of the slice is zero. When actual elements are specified , both length and capacity is equal to the number of actual elements specified.

Creating a slice from another slice or array

A slice can be created by re-slicing an exiting slice or array.

Create a slice from Array

The format for creating a new slice by re-slicing an existing array is

[n]sample[start:end]

The above operation will return a new slice from the array starting from index start to index end-1. So the element at index end is not included in the newly created slice. While re-slicing , both start and end index is optional.

  • The default value of the start index is zero
  • The default value of the end index is the length of the array

Let’s see an example.

package main

import "fmt"

func main() {
    numbers := [5]int{1, 2, 3, 4, 5}

    //Both start and end
    num1 := numbers[2:4]
    fmt.Println("Both start and end")
    fmt.Printf("num1=%v\n", num1)
    fmt.Printf("length=%d\n", len(num1))
    fmt.Printf("capacity=%d\n", cap(num1))

    //Only start
    num2 := numbers[2:]
    fmt.Println("\nOnly start")
    fmt.Printf("num1=%v\n", num2)
    fmt.Printf("length=%d\n", len(num2))
    fmt.Printf("capacity=%d\n", cap(num2))

    //Only end
    num3 := numbers[:3]
    fmt.Println("\nOnly end")
    fmt.Printf("num1=%v\n", num3)
    fmt.Printf("length=%d\n", len(num3))
    fmt.Printf("capacity=%d\n", cap(num3))

    //None
    num4 := numbers[:]
    fmt.Println("\nOnly end")
    fmt.Printf("num1=%v\n", num4)
    fmt.Printf("length=%d\n", len(num4))
    fmt.Printf("capacity=%d\n", cap(num4))
}

Output

Both start and end
num1=[3 4]
length=2
capacity=3

Only start
num1=[3 4 5]
length=3
capacity=3

Only end
num1=[1 2 3]
length=3
capacity=5

Only end
num1=[1 2 3 4 5]
length=5
capacity=5

Notice in above example that

  • length of newly created slice = (endstart)
  • capacity of newly created slice = (length_of_arraystart)

The num1 slice would look like

The newly created slices still refer the original array. To check this change element at any one of the index of the array and then reprint the slice

numbers[3] = 8
fmt.Printf("num1=%v\n", num2)
fmt.Printf("num3=%v\n", num3)
fmt.Printf("num4=%v\n", num4)

Here is the output:

num1=[3 8 5]
num3=[1 2 3 8]
num4=[1 2 3 8 5]

This proves that each of the new slice is still referring to the original array.

Create a slice from slice

Whatever we discussed about re-slicing from an array also applies here as well. See below example which illustrates same thing

package main

import "fmt"

func main() {
    numbers := []int{1, 2, 3, 4, 5}

    //Both start and end
    num1 := numbers[2:4]
    fmt.Println("Both start and end")
    fmt.Printf("num1=%v\n", num1)
    fmt.Printf("length=%d\n", len(num1))
    fmt.Printf("capacity=%d\n", cap(num1))

    //Only start
    num2 := numbers[2:]
    fmt.Println("\nOnly start")
    fmt.Printf("num1=%v\n", num2)
    fmt.Printf("length=%d\n", len(num2))
    fmt.Printf("capacity=%d\n", cap(num2))

    //Only end
    num3 := numbers[:3]
    fmt.Println("\nOnly end")
    fmt.Printf("num1=%v\n", num3)
    fmt.Printf("length=%d\n", len(num3))
    fmt.Printf("capacity=%d\n", cap(num3))

    //None
    num4 := numbers[:]
    fmt.Println("\nOnly end")
    fmt.Printf("num1=%v\n", num4)
    fmt.Printf("length=%d\n", len(num4))
    fmt.Printf("capacity=%d\n", cap(num4))
}

Output

Both start and end
num1=[3 4]
length=2
capacity=3

Only start
num1=[3 4 5]
length=3
capacity=3

Only end
num1=[1 2 3]
length=3
capacity=5

Only end
num1=[1 2 3 4 5]
length=5
capacity=5

Here also the newly created slices refer to the same underlying array that was being referred to by the original slice.  To check this change element at any one of the index of the original slice and then reprint all the newly created slices

numbers[3] = 8
fmt.Printf("num1=%v\n", num2)
fmt.Printf("num3=%v\n", num3)
fmt.Printf("num4=%v\n", num4)

Here is the output:

num1=[3 8 5]
num3=[1 2 3 8]
num4=[1 2 3 8 5]

Using the make function

make is a builtin function provided by go that can also be used to create a slice. Below is the signature of make function

func make([]{type}, length, capacity int) []{type}

Capacity is an optional parameter while creating slice using the make function. When capacity is omitted, the capacity of the slice is equal length specified for the slice. When using make function, behind the scenes go allocates an array equal to the capacity. All the elements of the allocated array are initialized with default zero value of the type. Let’s see a program illustrating this point.

package main

import "fmt"

func main() {
    numbers := make([]int, 3, 5)
    fmt.Printf("numbers=%v\n", numbers)
    fmt.Printf("length=%d\n", len(numbers))
    fmt.Printf("capacity=%d\n", cap(numbers))

    //With capacity ommited
    numbers = make([]int, 3)
    fmt.Println("\nCapacity Ommited")
    fmt.Printf("numbers=%v\n", numbers)
    fmt.Printf("length=%d\n", len(numbers))
    fmt.Printf("capacity=%d\n", cap(numbers))
}

Output

numbers=[0 0 0]
length=3
capacity=5

Capacity Ommited
numbers=[0 0 0]
length=3
capacity=3

Using the new function

new is a builtin function provided by go that can also be used to create a slice. It is not a very popular way of creating a slice as make is much more flexible in terms of functionalities . It is not generally used and also using new function returns a pointer to nil slice. Let’s see an example. In below example we are using the dereferencing operator ‘*’ as new function returns a pointer to the nil slice.

package main

import "fmt"

func main() {
    numbers := new([]int)
    fmt.Printf("numbers=%v\n", *numbers)
    fmt.Printf("length=%d\n", len(*numbers))
    fmt.Printf("capacity=%d\n", cap(*numbers))
}

Output

numbers=[]
length=0
capacity=0

Length vs Capacity

Before moving further, let’s emphasis on understanding the caveats of length and capacity. Let’s create a simple slice with capacity greater than length.

numbers := make([]int, 3, 5)
  • Accessing the slice behind its length will result in a run time error “Index out of range”. It doesn’t matter if the accessed index is within the capacity. So the below line will cause the run time error.
numbers[4] = 5
  • The length of the slice can be increased up to its capacity by re-slicing. So below re-slice will increase the length from 3 to 5.
numbers = numbers[0:5]
  • The length of the slice can also be decreased using re-slicing. So below re-slice will decrease the length from 3 to 2
numbers = numbers[0:2]
  • The advantage of having capacity is that array of size capacity can be pre-allocated during the initialization.  This is a performance boost as if more elements are needed to include in this array then space is already allocated for them.

Let’s see the program illustrating above points

package main

import "fmt"

func main() {
    numbers := make([]int, 3, 5)
    fmt.Printf("numbers=%v\n", numbers)
    fmt.Printf("length=%d\n", len(numbers))
    fmt.Printf("capacity=%d\n", cap(numbers))

    //This line will cause a runtime error index out of range [4] with length 3
    //numbers[4] = 5
   
    //Increasing the length from 3 to 5
    numbers = numbers[0:5]
    fmt.Println("\nIncreasing length from 3 to 5")
    fmt.Printf("numbers=%v\n", numbers)
    fmt.Printf("length=%d\n", len(numbers))
    fmt.Printf("capacity=%d\n", cap(numbers))

    //Decresing the length from 3 to 2
    numbers = numbers[0:2]
    fmt.Println("\nDecreasing length from 3 to 2")
    fmt.Printf("numbers=%v\n", numbers)
    fmt.Printf("length=%d\n", len(numbers))
    fmt.Printf("capacity=%d\n", cap(numbers))
}

Output

numbers=[0 0 0]
length=3
capacity=5

Increasing length from 3 to 5
numbers=[0 0 0 0 0]
length=5
capacity=5

Decreasing length from 3 to 2
numbers=[0 0]
length=2
capacity=5

Accessing and Modifying Slice Elements

A slice element can be accessed by specifying the index. Slice element can also be allotted a new value using the index. Also, note that any changes in the underlying array will reflect back in the slice as we have also seen above. Let’s see a small example of accessing and modifying

package main

import "fmt"

func main() {
    array := [5]int{1, 2, 3, 4, 5}
    slice := array[:]

    //Modifying the slice
    slice[1] = 7
    fmt.Println("Modifying Slice")
    fmt.Printf("Array=%v\n", array)
    fmt.Printf("Slice=%v\n", slice)

    //Modifying the array. Would reflect back in slice too
    array[1] = 2
    fmt.Println("\nModifying Underlying Array")
    fmt.Printf("Array=%v\n", array)
    fmt.Printf("Slice=%v\n", slice)
}

Output

Modifying Slice
Array=[1 7 3 4 5]
Slice=[1 7 3 4 5]

Modifying Underlying Array
Array=[1 2 3 4 5]
Slice=[1 2 3 4 5]

Different ways of iterating a slice

An array can be iterated using:

  • Using for loop
  • Using for-range loop

Let’s see a code example for both

package main

import "fmt"

func main() {
    letters := []string{"a", "b", "c"}
    //Using for loop
    fmt.Println("Using for loop")
    len := len(letters)
    for i := 0; i < len; i++ {
        fmt.Println(letters[i])
    }

    //Using for-range operator
    fmt.Println("\nUsing for-range loop")
    for i, letter := range letters {
        fmt.Printf("%d %s\n", i, letter)
    }
}

Output

Using for loop
a
b
c

Using for-range loop
0 a
1 b
2 c

Appending to a slice

go builtin package provides an append function that can be used to append to a slice at the end. Below is the signature of this function

func append(slice []Type, elems ...Type) []Type

The first argument is the slice itself. The second is the variable number of arguments which is

elems ...Type

'...' operator is the variadic syntax. So basically ...Type means It means that the append function can accept variable number of arguments of type Type. Below is the way for using this function. In below code we are appending 4 to a slice which has two elements. It appends at the end and returns the original slice. That is why we are collecting result again in numbers variable. It is also ok to assign the result to some other variable.

numbers := []int{1,2}
numbers = append(numbers, 4) //Slice will become [1, 2, 4]

It is also ok to append many number of elements because the second argument is the variadic argument.

numbers := []int{1,2}
numbers = append(numbers, 3, 4, 5) //Slice will become [1, 2, 3, 4, 5]

This function in the background increases the length and capacity of the slice. There are two cases

  • When slice length is less than capacity.

In this case, on using the append function,  the length of the slice will be increased  by one without any change in its capacity. Let's see a example

package main

import "fmt"

func main() {
    numbers := make([]int, 3, 5)
    numbers[0] = 1
    numbers[1] = 2
    numbers[2] = 3
    fmt.Printf("numbers=%v\n", numbers)
    fmt.Printf("length=%d\n", len(numbers))
    fmt.Printf("capacity=%d\n", cap(numbers))

    //Append number 4
    numbers = append(numbers, 4)
    fmt.Println("\nAppend Number 4")
    fmt.Printf("numbers=%v\n", numbers)
    fmt.Printf("length=%d\n", len(numbers))
    fmt.Printf("capacity=%d\n", cap(numbers))

    //Append number 5
    numbers = append(numbers, 4)
    fmt.Println("\nAppend Number 5")
    fmt.Printf("numbers=%v\n", numbers)
    fmt.Printf("length=%d\n", len(numbers))
    fmt.Printf("capacity=%d\n", cap(numbers))
}

Output

numbers=[1 2 3]
length=3
capacity=5

Append Number 4
numbers=[1 2 3 4]
length=4
capacity=5

Append Number 5
numbers=[1 2 3 4 4]
length=5
capacity=5

Capacity in all cases doesn't changes and it is 5 while length increases by 1.

  • When slice length is greater than capacity.

In this case since there is no more capacity, so no new elements can be accommodated.  So in this case under the hood an array of double the capacity will be allocated. The current array pointed by the  slice will be copied to that new array. Now the slice will starting pointing to this new array. Hence the capacity will be doubled and length will be increased by 1. Let's see a example

package main

import "fmt"

func main() {
    numbers := make([]int, 3, 3)
    numbers[0] = 1
    numbers[1] = 2
    numbers[2] = 3

    fmt.Printf("numbers=%v\n", numbers)
    fmt.Printf("length=%d\n", len(numbers))
    fmt.Printf("capacity=%d\n", cap(numbers))

    //Append number 4
    numbers = append(numbers, 4)
    fmt.Println("\nAppend Number 4")
    fmt.Printf("numbers=%v\n", numbers)
    fmt.Printf("length=%d\n", len(numbers))
    fmt.Printf("capacity=%d\n", cap(numbers))
}

Output

numbers=[1 2 3]
length=3
capacity=3

Append Number 4
numbers=[1 2 3 4]
length=4
capacity=6

Notice in above example that the capacity is doubled.

It is also possible to append one slice to another slice. Below is the format for that.

res := append(slice1, slice2...)

Notice '...' after the second slice. '...' is the operator which means that the argument is a variadic parameter. Meaning that during run time slice2 will be expanded to its individual elements which are passed as multiple arguments to the append function.

package main

import "fmt"

func main() {
    numbers1 := []int{1, 2}
    numbers2 := []int{3, 4}
    numbers := append(numbers1, numbers2...)
    fmt.Printf("numbers=%v\n", numbers)
    fmt.Printf("length=%d\n", len(numbers))
    fmt.Printf("capacity=%d\n", cap(numbers))
}

Output

numbers=[1 2 3 4]
length=4
capacity=4

Copy a slice

go builtin package provides copy function that can be used to copy a slice. Below is the signature of this function. It takes in two slices dst and src, and copies data from src to dst. It returns the number of elements copied.

func copy(dst, src []Type) int

There are two cases to be considered while using the copy function:

  • If the length of src is greater than the length of dst, then the number of elements copied is the length of dst
  • If the length of dst is greater than the length of src, then the number of elements copied is the length of src

Basically the number of elements copied is minimum of length of (src, dst). 

Also to note then once the copy is done then any change in dst will not reflect in src and vice versaLet's see an example of it.

package main

import "fmt"

func main() {
    src := []int{1, 2, 3, 4, 5}
    dst := make([]int, 5)

    numberOfElementsCopied := copy(dst, src)
    fmt.Printf("Number Of Elements Copied: %d\n", numberOfElementsCopied)
    fmt.Printf("dst: %v\n", dst)
    fmt.Printf("src: %v\n", src)

    //After changing numbers2
    dst[0] = 10
    fmt.Println("\nAfter changing dst")
    fmt.Printf("dst: %v\n", dst)
    fmt.Printf("src: %v\n", src)
}

Output

Number Of Elements Copied: 5
dst: [1 2 3 4 5]
src: [1 2 3 4 5]

After changing dst
dst: [10 2 3 4 5]
src: [1 2 3 4 5]

Nil Slice

The default zero value of a slice is nil. The length and capacity both of a nil slice is zero. Though it is possible to append to a nil slice as well. Let's see an example

package main

import "fmt"

func main() {
    var numbers []int
    fmt.Printf("numbers=%v\n", numbers)
    fmt.Printf("length=%d\n", len(numbers))
    fmt.Printf("capacity=%d\n", cap(numbers))
    numbers = append(numbers, 1)
    fmt.Printf("numbers=%v\n", numbers)
    fmt.Printf("length=%d\n", len(numbers))
    fmt.Printf("capacity=%d\n", cap(numbers))
}

Output

numbers=[]
length=0
capacity=0
numbers=[1]
length=1
capacity=1

Multidimensional Slices

As the multi-dimensional array is an array of arrays, similarly multi-dimensional slice is a slice of slices. To understand this, let's first look at the definition of a slice.

Data field in the slice header is a pointer to the underlying array. For a one dimensional slice, we have below declaration

oneDSlice := make([]int, 2)

To declare a two dimensional slice the declaration would be

twoDSlice = make([][]int, 2)

Above declaration means that we want to create a slice of 2 slices. Carefully understand this point. But wait a second here, we haven't specified the second dimension here, meaning what is the length of each of the inner 2 slices. In case of slice, each of the inner slice has to be explicitly intialized like below

for i := range twoDSlice {
    twoDSlice[i] = make([]int, 3)
}

So using range on the original slice, we specify the length each of 2 slices using make.  Below is one other way of doing the same but with slice elements specified

var twoDSlice = make([][]int, 2)
twoDSlice[0] = []int{1, 2, 3}
twoDSlice[1] = []int{4, 5, 6}

Basically, with the above declaration, we create a slice of 2*3 dimensions which is a two-dimensional slice. The same idea can be extended to two-dimension, three-dimension, and so on.

A complete working example of above two points

package main

import "fmt"

func main() {
    twoDSlice1 := make([][]int, 3)
    for i := range twoDSlice1 {
        twoDSlice1[i] = make([]int, 3)
    }
    fmt.Printf("Number of rows in slice: %d\n", len(twoDSlice1))
    fmt.Printf("Number of columns in arsliceray: %d\n", len(twoDSlice1[0]))
    fmt.Printf("Total number of elements in slice: %d\n", len(twoDSlice1)*len(twoDSlice1[0]))
    fmt.Println("First Slice")
    for _, row := range twoDSlice1 {
        for _, val := range row {
            fmt.Println(val)
        }
    }
    twoDSlice2 := make([][]int, 2)
    twoDSlice2[0] = []int{1, 2, 3}
    twoDSlice2[1] = []int{4, 5, 6}
    fmt.Println()
    fmt.Printf("Number of rows in slice: %d\n", len(twoDSlice2))
    fmt.Printf("Number of columns in arsliceray: %d\n", len(twoDSlice2[0]))
    fmt.Printf("Total number of elements in slice: %d\n", len(twoDSlice2)*len(twoDSlice2[0]))
    fmt.Println("Second Slice")
    for _, row := range twoDSlice2 {
        for _, val := range row {
            fmt.Println(val)
        }
    }
}

Output

Number of rows in slice: 2
Number of columns in arsliceray: 3
Total number of elements in slice: 6
First Slice
0
0
0
0
0
0

Number of rows in slice: 2
Number of columns in arsliceray: 3
Total number of elements in slice: 6
Second Slice
1
2
3
4
5
6

We mentioned above that we are creating a two-dimensional slice of 2*3 dimensions.  With that said the thought that might be coming to your mind is whether it is possible to have different lengths for inner slices. Yes, it is possible. Unlike arrays which have inner arrays of the same length, in case of slice since we initialize each of the inner slices individually, it is possible to have different length for inner slices

Let's see an example

package main

import "fmt"

func main() {
    twoDSlice := make([][]int, 2)
    twoDSlice[0] = []int{1, 2, 3}
    twoDSlice[1] = []int{4, 5}
  
    fmt.Printf("Number of rows in slice: %d\n", len(twoDSlice))
    fmt.Printf("Len of first row: %d\n", len(twoDSlice[0]))
    fmt.Printf("Len of second row: %d\n", len(twoDSlice[1]))
    fmt.Println("Traversing slice")
    for _, row := range twoDSlice {
        for _, val := range row {
            fmt.Println(val)
        }
    }
}

Output

Number of rows in slice: 2
Len of first row: 3
Len of second row: 2
Traversing slice
1
2
3
4
5

Let's see a small example of a three-dimensional slice as well. In the below program, we are creating a slice of 2*2*3 dimensions.

package main

import "fmt"

func main() {
    sample := make([][][]int, 2)
    for i := range sample {
        sample[i] = make([][]int, 2)
        for j := range sample[i] {
            sample[i][j] = make([]int, 3)
        }
    }
    
    fmt.Printf("Length of first dimension: %d\n", len(sample))
    fmt.Printf("Length of second dimension: %d\n", len(sample[0]))
    fmt.Printf("Length of third dimension: %d\n", len(sample[0][0]))
    fmt.Printf("Overall Dimension of the slice: %d*%d*%d\n", len(sample), len(sample[0]), len(sample[0][0]))
    fmt.Printf("Total number of elements in slice: %d\n", len(sample)*len(sample[0])*len(sample[0][0]))
    for _, first := range sample {
        for _, second := range first {
            for _, value := range second {
                fmt.Println(value)
            }
        }
    }
}

Output

Length of first dimension: 2
Length of second dimension: 2
Length of third dimension: 3
Overall Dimension of the slice: 2*2*3
Total number of elements in slice: 12
0
0
0
0
0
0
0
0
0
0
0
0

Conclusion

This is all about slice in golang. Hope you have liked this article. Please share feedback/improvements/mistakes in comments

Next Tutorial – Maps
Previous Tutorial – Array

The post Slice in Go (Golang) appeared first on Welcome To Golang By Example.

]]>
https://vikasboss.github.io/slice-in-golang/feed/ 8 2181
Print an array or slice elements in Go (Golang) https://vikasboss.github.io/print-an-array-or-slice-elements-golang/ https://vikasboss.github.io/print-an-array-or-slice-elements-golang/#respond Mon, 18 May 2020 14:22:18 +0000 https://vikasboss.github.io/?p=2177 Overview The way we print an array or slice is same. Let’s look at both one by one Print a Slice Print slice elements together Using fmt.Println and fmt.Printf Output Print individual...

The post Print an array or slice elements in Go (Golang) appeared first on Welcome To Golang By Example.

]]>
Overview

The way we print an array or slice is same. Let’s look at both one by one

Print a Slice

Print slice elements together

Using

  • fmt.Println and
  • fmt.Printf
package main
import "fmt"
func main() {
    numbers := []int{1, 2, 3}
    fmt.Println(numbers)
    fmt.Printf("Numbers: %v", numbers)
}

Output

[1 2 3]
Numbers: [1 2 3]

Print individual slice elements

Using

  • for-range loop
package main
import "fmt"
func main() {
    numbers := []int{1, 2, 3}
    for _, num := range numbers {
        fmt.Println(num)
    }
}

Output

1
2
3

Print a Array

Print array elements together

Using

  • fmt.Println and
  • fmt.Printf
package main
import "fmt"
func main() {
    numbers := [3]int{1, 2, 3}
    fmt.Println(numbers)
    fmt.Printf("Numbers: %v", numbers)
}

Output

[1 2 3]
Numbers: [1 2 3]

Print individual array elements:

Using

  • for-range loop
package main
import "fmt"
func main() {
    numbers := [3]int{1, 2, 3}
    for _, num := range numbers {
        fmt.Println(num)
    }
}

Output

1
2
3

The post Print an array or slice elements in Go (Golang) appeared first on Welcome To Golang By Example.

]]>
https://vikasboss.github.io/print-an-array-or-slice-elements-golang/feed/ 0 2177
Two Dimensional (2d) and Multi-Dimensional Array and Slice in Go (Golang) https://vikasboss.github.io/two-dimensional-array-slice-golang/ https://vikasboss.github.io/two-dimensional-array-slice-golang/#respond Fri, 15 May 2020 21:25:39 +0000 https://vikasboss.github.io/?p=2146 In go multi-dimension is possible for both array and slice. Let’s see both of them in detail. Multi-Dimensional Arrays Overview Below is the format for declaring a multidimensional dimensional array where len1...

The post Two Dimensional (2d) and Multi-Dimensional Array and Slice in Go (Golang) appeared first on Welcome To Golang By Example.

]]>
In go multi-dimension is possible for both array and slice. Let’s see both of them in detail.

Multi-Dimensional Arrays

Overview

Below is the format for declaring a multidimensional dimensional array

[len1][len2][len3]....[lenN]T{}

where

  • len1 , len2 .. lenN are length of each of the dimensions
  • T is the data type

All the rules that apply to the one-dimensional array also apply to the multidimensional array as well. It is also possible to specify the array elements during the declaration. In case the array elements are not specified during declaration, then all the array elements are allotted the default zero value of the <data_type>

Below is the format for declaring a two dimensional array with array elements specified.

var sample = [len1][len2]T{{a11, a12 .. a1y},
                       {a21, a22 .. a2y},
                       {.. },
                       {ax1, ax2 .. axy}}     

where

  • len1 denotes the number of rows
  • len2 denotes the number of columns
  • aij denotes an element present at i row and j column
  • T is the data type

Let’s see a small example illustrating above points:

package main

import "fmt"

func main() {

    sample := [2][3]int{{1, 2, 3}, {4, 5, 6}}

    fmt.Printf("Number of rows in array: %d\n", len(sample))
    fmt.Printf("Number of columns in array: %d\n", len(sample[0]))
    fmt.Printf("Total number of elements in array: %d\n", len(sample)*len(sample[0]))

    fmt.Println("Traversing Array")
    for _, row := range sample {
        for _, val := range row {
            fmt.Println(val)
        }
    }
}

Output

Number of rows in array: 2
Number of columns in array: 3
Total number of elements in array: 6
Traversing Array
1
2
3
4
5
6

Notice in the above program how are we able to get the number of rows, column and also the total number of elements in the array

  • Number of rows = len(sample)
  • Number of columns = len(sample[0])
  • Number of total elements = len(sample)*len(sample[0])

The same idea can be extended to three dimensions, four dimensions, and so on. Let’s see a small example of three dimensional array as well. In below program we are creating a 2*2*3 dimensional array.

package main

import "fmt"

func main() {
    sample := [2][2][3]int{{{1, 2, 3}, {4, 5, 6}}, {{7, 8, 9}, {10, 11, 12}}}

    fmt.Printf("Length of first dimension: %d\n", len(sample))
    fmt.Printf("Length of second dimension: %d\n", len(sample[0]))
    fmt.Printf("Length of third dimension: %d\n", len(sample[0][0]))

    fmt.Printf("Overall Dimension of the array: %d*%d*%d\n", len(sample), len(sample[0]), len(sample[0][0]))
    fmt.Printf("Total number of elements in array: %d\n", len(sample)*len(sample[0])*len(sample[0][0]))

    for _, first := range sample {
        for _, second := range first {
            for _, value := range second {
                fmt.Println(value)
            }
        }
    }
}

Output

Length of first dimension: 2
Length of second dimension: 2
Length of third dimension: 3
Overall Dimension of the array: 2*2*3
Total number of elements in array: 12
1
2
3
4
5
6
7
8
9
10
11
12

Accessing elements of a multi dimensional array

An element of a multi-dimensional array can be accessed using the index of each of the dimensions. For example, a two-dimensional array can be accessed by provided its row index and column index. Once we are able to access them using the index of each of the dimensions, then it is also possible to assign a new value to it as well. Let’s see a program

package main

import "fmt"

func main() {
    sample := [2][3]int{{1, 2, 3}, {4, 5, 6}}
    //Print array element
    fmt.Println(sample[0][0])
    fmt.Println(sample[0][1])
    fmt.Println(sample[0][2])
    fmt.Println(sample[1][0])
    fmt.Println(sample[1][1])
    fmt.Println(sample[1][2])
    
    //Assign new values
    sample[0][0] = 6
    sample[0][1] = 5
    sample[0][2] = 4
    sample[1][0] = 3
    sample[1][1] = 2
    sample[1][2] = 1

    fmt.Println()
    fmt.Println(sample[0][0])
    fmt.Println(sample[0][1])
    fmt.Println(sample[0][2])
    fmt.Println(sample[1][0])
    fmt.Println(sample[1][1])
    fmt.Println(sample[1][2])
}

Output

1
2
3
4
5
6

6
5
4
3
2
1

Traversal of a multidimensional array

A multidimensional array can be traversed using:

  • for-range loop
  • for loop

Let’s see a code example for traversal of a two dimensional array.

package main

import "fmt"

func main() {
    sample := [2][3]int{{1, 2, 3}, {4, 5, 6}}
    fmt.Println("Using for-range")
    for _, row := range sample {
        for _, val := range row {
            fmt.Println(val)
        }
    }

    fmt.Println("\nUsing for loop")
    for i := 0; i < 2; i++ {
        for j := 0; j < 3; j++ {
            fmt.Println(sample[i][j])
        }
    }

    fmt.Println("\nUsing for loop - Second way")
    for i := 0; i < len(sample); i++ {
        for j := 0; j < len(sample[i]); j++ {
            fmt.Println(sample[i][j])
        }
    }
}

Output

Using for-rage
1
2
3
4
5
6

Using for loop
1
2
3
4
5
6

Using for loop 
1
2
3
4
5
6

Some points to note about above program

  • We have to use a nested range for traversal using a for-range loop. The first range traverses each of the rows. The second range traverses the individual array present at that row
  • The same goes for iterating using for loop.
  • len(sample) gives the number of rows.
  • len(sample[i]) gives the number of columns present at row i.
  • The same idea can be extended to three dimensional, four-dimensional array element too.

How multidimensional array is stored in memory

Memory allocated for array is contiguous irrespective of weather an array is one dimensional or two dimensional. For example in case of two dimension array the second row starts in memory where the first row ends. Let's see a program illustrating this point

package main

import "fmt"

func main() {
    sample := [2][3]byte{}

    fmt.Println("First row")
    fmt.Println(&sample[0][0])
    fmt.Println(&sample[0][1])
    fmt.Println(&sample[0][2])

    fmt.Println("\nSecond row")
    fmt.Println(&sample[1][0])
    fmt.Println(&sample[1][1])
    fmt.Println(&sample[1][2])
}

Output

First row
0xc0000b4002
0xc0000b4003
0xc0000b4004

Second row
0xc0000b4005
0xc0000b4006
0xc0000b4007

Notice all the address are contiguous. And the second row starts where the first row ends.

Multi-dimensional Slices

Overview

As the multidimensional array is an array of arrays, similarly multi-dimensional slice is a slice of slices. To understand this, let's first look at the definition of a slice. A slice points to an underlying array and is internally represented by a slice header. A slice header is a struct which looks like  this

type SliceHeader struct {
        Data uintptr
        Len  int
        Cap  int
}

Data field in slice header is pointer to the underlying array. For a one dimensional slice, we have below declaration

oneDSlice := make([]int, 2)

To declare a two dimensional slice the declaration would be

twoDSlice := make([][]int, 2)

Above declaration means that we want to create a slice of 2 slices. Carefully understand this point. But wait a second here, we haven't specified the second dimension here, meaning what is the length of each of the inner 2 slices. In case of slice, each of the inner slice has to be explicitly intialised like below

for i := range twoDSlice {
    twoDSlice[i] = make([]int, 3)
}

So using range on the original slice, we specify the length each of 2 slices using make.  Below is one other way of doing the same but with slice elements specified

var twoDSlice = make([][]int, 2)
twoDSlice[0] = []int{1, 2, 3}
twoDSlice[1] = []int{4, 5, 6}

Basically, with the above declaration, we create a slice of 2*3 dimensions which is a two-dimensional slice. The same idea can be extended to two-dimension, three-dimension, and so on.

A complete working example of above two points

package main

import "fmt"

func main() {
    twoDSlice1 := make([][]int, 3)
    for i := range twoDSlice1 {
        twoDSlice1[i] = make([]int, 3)
    }
    fmt.Printf("Number of rows in slice: %d\n", len(twoDSlice1))
    fmt.Printf("Number of columns in arsliceray: %d\n", len(twoDSlice1[0]))
    fmt.Printf("Total number of elements in slice: %d\n", len(twoDSlice1)*len(twoDSlice1[0]))
    fmt.Println("First Slice")
    for _, row := range twoDSlice1 {
        for _, val := range row {
            fmt.Println(val)
        }
    }
    twoDSlice2 := make([][]int, 2)
    twoDSlice2[0] = []int{1, 2, 3}
    twoDSlice2[1] = []int{4, 5, 6}
    fmt.Println()
    fmt.Printf("Number of rows in slice: %d\n", len(twoDSlice2))
    fmt.Printf("Number of columns in arsliceray: %d\n", len(twoDSlice2[0]))
    fmt.Printf("Total number of elements in slice: %d\n", len(twoDSlice2)*len(twoDSlice2[0]))
    fmt.Println("Second Slice")
    for _, row := range twoDSlice2 {
        for _, val := range row {
            fmt.Println(val)
        }
    }
}

Output

Number of rows in slice: 2
Number of columns in arsliceray: 3
Total number of elements in slice: 6
First Slice
0
0
0
0
0
0

Number of rows in slice: 2
Number of columns in arsliceray: 3
Total number of elements in slice: 6
Second Slice
1
2
3
4
5
6

We mentioned above that we are creating a two-dimensional slice of 2*3 dimensions.  With that said the thought that might be coming to your mind is whether it is possible to have different lengths for inner slices. Yes, it is possible. Unlike arrays which have inner arrays of the same length, in case of slice since we initialize each of the inner slices individually, it is possible to have different length for inner slices

Let's see an example

package main

import "fmt"

func main() {
    twoDSlice := make([][]int, 2)
    twoDSlice[0] = []int{1, 2, 3}
    twoDSlice[1] = []int{4, 5}
  
    fmt.Printf("Number of rows in slice: %d\n", len(twoDSlice))
    fmt.Printf("Len of first row: %d\n", len(twoDSlice[0]))
    fmt.Printf("Len of second row: %d\n", len(twoDSlice[1]))
    fmt.Println("Traversing slice")
    for _, row := range twoDSlice {
        for _, val := range row {
            fmt.Println(val)
        }
    }
}

Output

Number of rows in slice: 2
Len of first row: 3
Len of second row: 2
Traversing slice
1
2
3
4
5

Let's see a small example of a three-dimensional slice as well. In the below program, we are creating a slice of 2*2*3 dimensions.

package main

import "fmt"

func main() {
    sample := make([][][]int, 2)
    for i := range sample {
        sample[i] = make([][]int, 2)
        for j := range sample[i] {
            sample[i][j] = make([]int, 3)
        }
    }
    
    fmt.Printf("Length of first dimension: %d\n", len(sample))
    fmt.Printf("Length of second dimension: %d\n", len(sample[0]))
    fmt.Printf("Length of third dimension: %d\n", len(sample[0][0]))
    fmt.Printf("Overall Dimension of the slice: %d*%d*%d\n", len(sample), len(sample[0]), len(sample[0][0]))
    fmt.Printf("Total number of elements in slice: %d\n", len(sample)*len(sample[0])*len(sample[0][0]))
    for _, first := range sample {
        for _, second := range first {
            for _, value := range second {
                fmt.Println(value)
            }
        }
    }
}

Output

Length of first dimension: 2
Length of second dimension: 2
Length of third dimension: 3
Overall Dimension of the slice: 2*2*3
Total number of elements in slice: 12
0
0
0
0
0
0
0
0
0
0
0

Accessing Multi-Dimensional Slice elements

Accessing slice elements is the same as accessing elements of an array. Let's see an example

package main

import "fmt"

func main() {
    sample := make([][]int, 2)
    sample[0] = []int{1, 2, 3}
    sample[1] = []int{4, 5, 6}

    //Print array element
    fmt.Println(sample[0][0])
    fmt.Println(sample[0][1])
    fmt.Println(sample[0][2])
    fmt.Println(sample[1][0])
    fmt.Println(sample[1][1])
    fmt.Println(sample[1][2])

    //Assign new values
    sample[0][0] = 6
    sample[0][1] = 5
    sample[0][2] = 4
    sample[1][0] = 3
    sample[1][1] = 2
    sample[1][2] = 1

    fmt.Println()
    fmt.Println(sample[0][0])
    fmt.Println(sample[0][1])
    fmt.Println(sample[0][2])
    fmt.Println(sample[1][0])
    fmt.Println(sample[1][1])
    fmt.Println(sample[1][2])
}

Output

1
2
3
4
5
6

6
5
4
3
2
1

Traversal of a multi dimensional slice.

Traversing a multidimensional slice is the same as traversing a multi-dimensional array. A multidimensional slice can be traversed using

  • for-range loop
  • for loop

Let's see an example:

package main

import "fmt"

func main() {
    sample := make([][]int, 2)
    sample[0] = []int{1, 2, 3}
    sample[1] = []int{4, 5, 6}
    fmt.Println("Using for-range")
    for _, row := range sample {
        for _, val := range row {
            fmt.Println(val)
        }
    }

    fmt.Println("\nUsing for loop - Second way")
    for i := 0; i < len(sample); i++ {
        for j := 0; j < len(sample[i]); j++ {
            fmt.Println(sample[i][j])
        }
    }
}

Output

How multidimensional slice is stored in memory

Since in the case of the slice, each of the inner slices is initialized separately hence it is possible that inner slice might not be contiguous in memory with respect to each other. Although each of the elements within each of inner slice will be at the contiguous location. Let's see a program illustrating this point.

package main

import "fmt"

func main() {
    sample := make([][]byte, 2)
    sample[0] = make([]byte, 3)

    //testVariable := "s"
    //fmt.Println(testVariable)
    
    sample[1] = make([]byte, 3)

    fmt.Println("First row")
    fmt.Println(&sample[0][0])
    fmt.Println(&sample[0][1])
    fmt.Println(&sample[0][2])

    fmt.Println("\nSecond row")
    fmt.Println(&sample[1][0])
    fmt.Println(&sample[1][1])
    fmt.Println(&sample[1][2])
}

Output

First row
0xc000018072
0xc000018073
0xc000018074

Second row
0xc000018080
0xc000018081
0xc000018082

Please Note: There is a caveat in the above program. Since the second inner slice is initialized just after the first inner slice, there is a possibility that the address allotted to both of them is contiguous. It can happen but not always. Uncomment the line for test variable and then both the inner slice will not be allotted contiguous address. In the case of an array, all inner arrays will be stored at contiguous locations always.

Conclusion

This is all about multidimensional array and slice in golang. I hope you have liked this article. Please share the feedback in the comments.

The post Two Dimensional (2d) and Multi-Dimensional Array and Slice in Go (Golang) appeared first on Welcome To Golang By Example.

]]>
https://vikasboss.github.io/two-dimensional-array-slice-golang/feed/ 0 2146
Generate a random array/slice of n integers in Go (Golang) https://vikasboss.github.io/generate-random-array-slice-golang/ https://vikasboss.github.io/generate-random-array-slice-golang/#respond Thu, 02 Apr 2020 07:06:06 +0000 https://vikasboss.github.io/?p=1940 Overview math/rand package of GO provides a Perm method that can be used generate the pseudo-random slice of n integers. The array will be pseudo-random permutation of the integers in the range...

The post Generate a random array/slice of n integers in Go (Golang) appeared first on Welcome To Golang By Example.

]]>
Overview

math/rand package of GO provides a Perm method that can be used generate the pseudo-random slice of n integers. The array will be pseudo-random permutation of the integers in the range [0,n).

To know more about what pseudo-random number means, checkout this post – https://vikasboss.github.io/generate-random-number-golang
Below is the signature of the function. It takes a number n as input and returns the permuted slice.

func Perm(n int) []int

Code:

package main

import (
    "fmt"
    "math/rand"
    "time"
)

func main() {
    //Provide seed
    rand.Seed(time.Now().Unix())

    //Generate a random array of length n
    fmt.Println(rand.Perm(10))
    fmt.Println(rand.Perm(10))
}

Output:

[6 0 1 5 9 4 2 3 7 8]
[9 8 5 0 3 4 6 7 2 1]

The post Generate a random array/slice of n integers in Go (Golang) appeared first on Welcome To Golang By Example.

]]>
https://vikasboss.github.io/generate-random-array-slice-golang/feed/ 0 1940
Shuffle a slice or array in Go (Golang) https://vikasboss.github.io/shuffle-slice-or-array-go/ https://vikasboss.github.io/shuffle-slice-or-array-go/#respond Thu, 02 Apr 2020 06:53:18 +0000 https://vikasboss.github.io/?p=1928 Overview math/rand package of go provides a Shuffle method that can be used shuffle an array or a slice. This method pseudo-randomizes the order of elements using the default source. pseudo-randomizes means...

The post Shuffle a slice or array in Go (Golang) appeared first on Welcome To Golang By Example.

]]>
Overview

math/rand package of go provides a Shuffle method that can be used shuffle an array or a slice. This method pseudo-randomizes the order of elements using the default source. pseudo-randomizes means that for a fixed input seed it will generate the same randomization. That is why in our program we will initialize the rand package with a different seed every time.

Below is the signature of the function.

func Shuffle(n int, swap func(i, j int))

This function takes in arguments

  • First is the length of the array or slice.
  • The second is a swap function that will be called for different indexes i and j. You need to provide your own swap function that will swap your elements in the array.

Also note that this function will panic if n<0. Let’s look at the code.

Code:

package main

import (
    "fmt"
    "math/rand"
    "time"
)

func main() {
    rand.Seed(time.Now().Unix())

    in := []int{2, 3, 5, 8}
    rand.Shuffle(len(in), func(i, j int) {
        in[i], in[j] = in[j], in[i]
    })
    fmt.Println(in)

    rand.Shuffle(len(in), func(i, j int) {
        in[i], in[j] = in[j], in[i]
    })
    fmt.Println(in)
}

Output:

It can produce a different output on your machine.

[5 3 2 8]
[3 5 8 2]

The post Shuffle a slice or array in Go (Golang) appeared first on Welcome To Golang By Example.

]]>
https://vikasboss.github.io/shuffle-slice-or-array-go/feed/ 0 1928
Pick a random element in an array or slice in Go (Golang) https://vikasboss.github.io/pick-random-element-array-slice-go/ https://vikasboss.github.io/pick-random-element-array-slice-go/#respond Tue, 31 Mar 2020 15:55:50 +0000 https://vikasboss.github.io/?p=1912 Overview ‘mat/rand’ package of golang contains a Intn function that can be used to generate a pseudo-random number between [0,n). Bracket at the end means that n is exclusive. This function can...

The post Pick a random element in an array or slice in Go (Golang) appeared first on Welcome To Golang By Example.

]]>
Overview

‘mat/rand’ package of golang contains a Intn function that can be used to generate a pseudo-random number between [0,n). Bracket at the end means that n is exclusive. This function can be utilized to pick a random element in an array or slice of int or string.

To know more about what pseudo-random number means, checkout this post – https://vikasboss.github.io/generate-random-number-golang

Below is the signature of this method. It takes input a number n and will return a number x in range 0<=x<n.

func Intn(n int) int

Code

We can directly index an element in a slice of int. See below program for picking up random from a slice of int.

package main

import (
    "fmt"
    "math/rand"
)

func main() {
    in := []int{2, 5, 6}
    randomIndex := rand.Intn(len(in))
    pick := in[randomIndex]
    fmt.Println(pick)
}

Output:

Between 2, 5 or 6

The post Pick a random element in an array or slice in Go (Golang) appeared first on Welcome To Golang By Example.

]]>
https://vikasboss.github.io/pick-random-element-array-slice-go/feed/ 0 1912
Go: Different ways of iterating over an Array and Slice https://vikasboss.github.io/go-different-ways-iterating-array-slice/ https://vikasboss.github.io/go-different-ways-iterating-array-slice/#respond Sun, 20 Oct 2019 07:20:42 +0000 https://vikasboss.github.io/?p=318 Go provides many different ways of iterating over an array. All examples below are also applicable to slice. Let’s define an array of letters first Using the range operator With index and...

The post Go: Different ways of iterating over an Array and Slice appeared first on Welcome To Golang By Example.

]]>
Go provides many different ways of iterating over an array. All examples below are also applicable to slice.

Let’s define an array of letters first

letters := []string{"a", "b", "c", "d", "e"}

Using the range operator

  • With index and value
for i, letter := range letters {
   fmt.Printf("%d %s\n", i, letter)
}
  • Only Value
for _, letter := range letters {
   fmt.Println(letter)
}
  • Only index
for i := range letters {
   fmt.Println(i)
}
  • Without value and index. Just print array values
i := 0
for range letters {
  fmt.Println(i)
  i++
}

Using Only For operator

  • Single initialization and post
len := len(letters)
for i := 0; i < len; i++ {
  fmt.Println(letters[i])
}
  • Multiple initialization and post statement
len := len(letters)
for i, j := 0, len; i < j; i, j = i+1, j-1 {
  fmt.Println(letters[i])
}

The post Go: Different ways of iterating over an Array and Slice appeared first on Welcome To Golang By Example.

]]>
https://vikasboss.github.io/go-different-ways-iterating-array-slice/feed/ 0 318