03. Arrays, Slices, and Maps

Table of contents

Array
An array is a collection of similar data elements that are stored at contiguous memory locations.
Arrays are also known as homogeneous data types since we can store elements of a single datatype in one array and not different datatype in one single array.
Why we need arrays?
In programming, most of the time we need to store large amounts of data of similar type. For example, let’s say we want to store marks secured by students in three subjects. So, instead of creating three different variables to store these values, we can simply create an array called grades and can store these marks together.
Arrays are fixed length, once initialize, we cannot change the length of the array.
Elements should be of the same data type.
Array in golang, has a pointer that points to the first element of the array.
Array, also has a property called length, which denotes the number of elements, in the array.
Also has a property called capacity, which denotes the number of elements that it can contain.
In case of array, Length and capacity are same.
Array declaration syntax
var <array-name> <[array-size]> <array-datatype>
example. var grades [5] int
; var fruits [3] string
Array declaration
func main() {
// Declare the arrays
var grades [5]int
var fruits [3]string
// Print the arrays
fmt.Println("Grades:", grades)
fmt.Println("Fruits:", fruits)
}
/* Output:
Grades: [0 0 0 0 0]
Fruits: [ ]
*/
Array initialization
var grades [5] int = [5]int{10,20,30}
grades := [5]int{10,20,30}
» Short-hand declarationgrades := […]int{10,20,30}
» Using ellipses
func main() {
// Declare and initialize the arrays
var fruits [2]string = [2]string{"apples", "oranges"}
marks := [3]int{98, 88, 97}
names := [...]string{"Rechal", "Monu", "Bini"}
// Print the arrays
fmt.Println("Fruits:", fruits)
fmt.Println("Marks:", marks)
fmt.Println("Names:", names)
}
/*
Fruits: [apples oranges]
Marks: [98 88 97]
Names: [Rechal Monu Bini]
*/
len()
- The length of an array refers to the number of elements can store in an array.
func main() {
// Declare and initialize the array
var fruits [2]string = [2]string{"apple", "banana"}
// Print the length of the array
fmt.Println("Length of fruits array:", len(fruits))
}
// Length of fruits array: 2
Indexes in array
An Array is also numbered, and these numbers are called array index.
First element of an array is of index 0, and last element is index of
array length - 1
.Array index lies:
0 <= index <= len - 1
func main() {
var fruits [5]string = [5]string{"apples", "oranges", "grapes", "mango", "banana"}
fmt.Println(fruits[2])
}
// grapes
func main() {
var fruits [5]string = [5]string{"apples", "oranges", "grapes", "mango", "banana"}
fmt.Println(fruits[6]) // This line will cause an error
}
// invalid array index 6 (out of bounds for 5-element array)
Changing the value of an array
func main() {
var grades [5]int = [5]int{98, 88, 97, 58, 96}
fmt.Println(grades[3]) // Prints the initial value at index 3
grades[3] = 88 // Updates the value at index 3
fmt.Println(grades[3]) // Prints the updated value at index 3
}
/*
58
88
*/
Looping through an array using for
func main() {
var grades [5]int = [5]int{98, 88, 97, 58, 96}
for i := 0; i < len(grades); i++ {
fmt.Println(grades[i])
}
}
/*
98
88
97
58
96
*/
Looping through an array using range
range
keywords is mainly used infor loops
in order to iterate over all elements of anarray, slices, and maps
.For arrays,
range
sets the scope of iteration up to the length of the array.In case of arrays and slices, from
range
keywords, first value returned is the index, and second value is the element itself.
func main() {
var grades [5]int = [5]int{98, 88, 97, 58, 96}
for index, element := range grades {
fmt.Println(index, ":", element)
}
}
/*
0 : 98
1 : 88
2 : 97
3 : 58
4 : 96
*/
Multidimensional arrays
More than one dimension
Array of arrays
An array that has multiple level
Simplest multidimensional array is 2D array
func main() {
arr := [3][2]int{{2, 4}, {5, 7}, {8, 9}}
fmt.Println(arr[2][1])
}
// Output: 9
Slices
A slice is defined as a continuous segment of an underlying array and provides access to a numbered sequence of elements from that array.
Slices provide access to parts of an array in sequential order.
They are more flexible and more powerful than an array.
As arrays has limitations of being fixed size, slices are variable typed (We can add or remove elements from a slice).
Component of an slice
- Pointer, 2. Length, 3. Capacity
Pointer: Pointer is used to point to the first element of the array, that is accible through that slice.
- Pointers are variable that holds memory address.
Slices have both length and capacity.
Length of a slice is the number of elements it contains.
The capacity of a slice is the number of elements in the underlying array, counting from the first element in the slice.
len()
to get length,cap()
to get capacity of a slice.
Declaring and initializing a slice
<slice_name> := []<data_type>{<values>}
» No need to mention size.
grades := []int{89, 90, 85}
func main() {
grades := []int{89, 90, 85}
fmt.Println(grades)
}
// [89 90 85]
Slice from an array
array [start_index : end_index]
- Starting index is included but exding index is excluded.
Example: array[0 : 3]
; arr[1 : 6]
; arr[ : 4]
; arr[ : ]
If we don’t mention lower bound/ starting index, slice will start from 0th index by default.
If we don’t mention both the index (starting and ending), the entire array will be slices for us.
func main() {
arr := [10]int{10, 20, 30, 40, 50, 60, 70, 80, 90, 100}
slice_1 := arr[0:8]
fmt.Println(slice_1)
}
// [10 20 30 40 50 60 70 80]
func main() {
arr := [10]int{10, 20, 30, 40, 50, 60, 70, 80, 90, 100}
slice_1 := arr[1:8]
fmt.Println(slice_1)
slice_2 := slice_1[0:3]
fmt.Println(slice_2)
}
/*
[20 30 40 50 60 70 80]
[20 30 40]
*/
Declaring and initializing a slice using make()
slice := make([]<data_type>, length, capacity)
Capacity is optional here.
slice : make ([]int, 5, 10)
func main() {
slice := make([]int, 5, 8)
fmt.Println(slice)
fmt.Println(len(slice))
fmt.Println(cap(slice))
}
/*
[0 0 0 0 0]
5
8
*/
- Capacity function (
cap()
) are mostly use for slice, however it can be use for array as well. but the thing is, capacity of an array is equal o the length of that array.
func main() {
arr := [10]int{10, 20, 30, 40, 50, 60, 70, 80, 90, 100}
slice := arr[1:8]
fmt.Println(cap(arr))
fmt.Println(cap(slice))
}
/*
10
9
*/
As slice is a reference of an array, when we change the value of a slice, that will affect on that array as well.
func main() {
arr := [5]int{10, 20, 30, 40, 50}
slice := arr[:3]
fmt.Println(arr)
fmt.Println(slice)
slice[1] = 800
fmt.Println("After modification")
fmt.Println(arr)
fmt.Println(slice)
}
/*
[10 20 30 40 50]
[10 20 30]
After modification
[10 800 30 40 50]
[10 800 30]
*/
Appending to a slice
func append(s []T, vs …T) []T
First parameter »
s []T
» slice of some datatype.Rest are »
vs …T
» Values of the same datatype.Resulting value of this append function is »
[]T
» a slice containing all the elements of the original slice plus the provided values.
If the underlying array is too small to fit the new values, a bigger array will be allocated. Now this new slice that will be returned will have two times the initial capacity. If the initial capacity could not contain all the elements.
func main() {
arr := [4]int{10, 20, 30, 40}
slice := arr[1:3]
fmt.Println(slice) // Output: [20 30]
fmt.Println(len(slice)) // Output: 2
fmt.Println(cap(slice)) // Output: 3
slice = append(slice, 900, -90, 50)
fmt.Println(slice) // Output: [20 30 900 -90 50]
fmt.Println(len(slice)) // Output: 5
fmt.Println(cap(slice)) // Output: 6 (or more, depending on Go's internal allocation strategy)
}
Appending a slice to another slice
slice = append(slice, anotherSlice…)
- Three dots
...
used for variadic functions. That can take an arbitrary number of arguments.
func main() {
arr := [5]int{10, 20, 30, 40, 50}
slice := arr[:2] // This creates a slice with elements [10, 20]
arr_2 := [5]int{5, 15, 25, 35, 45}
slice_2 := arr_2[:2] // This creates a slice with elements [5, 15]
new_slice := append(slice, slice_2...) // Appends elements of slice_2 to slice
fmt.Println(new_slice) // Output: [10 20 5 15]
}
Deleting from a slice
func main() {
arr := [5]int{10, 20, 30, 40, 50}
i := 2
fmt.Println(arr) // Output: [10 20 30 40 50]
slice := arr[:i] // This creates a slice with elements [10, 20]
slice_2 := arr[i+1:] // This creates a slice with elements [40, 50]
new_slice := append(slice, slice_2...) // Appends elements of slice_2 to slice
fmt.Println(new_slice) // Output: [10 20 40 50]
}
Copying one slice to another
func copy(dest, src []Type) int
copying into a destination slice from a source slice.
It also returns, the number of element that has been copied, which is the minimum of the length of the destination slice or the length of the source slice.
num := copy(dest_slice, src_slice)
- Both slice need to be of same datatype.
func main() {
src_slice := []int{10, 20, 30, 40, 50}
dest_slice := make([]int, 3)
num := copy(dest_slice, src_slice)
fmt.Println(dest_slice) // Output: [10 20 30]
fmt.Println("Number of elements copied: ", num) // Output: Number of elements copied: 3
}
Looping through a slice using range
func main() {
arr := []int{10, 20, 30, 40, 50}
for index, value := range arr {
fmt.Println(index, ":→", value)
}
}
/*
0 :→ 10
1 :→ 20
2 :→ 30
3 :→ 40
4 :→ 50
*/
Replacing the first return value using underscore (_)
func main() {
arr := []int{10, 20, 30, 40, 50}
for _, value := range arr {
fmt.Println(value)
}
}
/*
10
20
30
40
50
*/
Maps
A map is a data structure that provides you with an unordered collection of key-value pairs.
They are also sometimes called associative arrays in PHP, or hash tables in Java, or dictionaries in Python.
They are used to look up a value by its associated key. We store values into map based on a key.
The strength of a map is its ability to retrieve data quickly based on the key.
A key works like an index that points to the value we associate with that key.
Go maps are implemented by hash tables, and they have efficient get, add, and delete operations.
Declaring and initializing a map
var <map_name> map[<key_data_type>]<value_data_type>
var my_map map[string]int
» This index creates a nil map. In maps, the zero value of the map is nil, and a nil map does not contain any key.
- If we try to add a key-value pair to a nil-map, the compiler will throw us a runtime error.
Creating a map
func main() {
var codes map[string]string
codes["en"] = "english"
fmt.Println(codes)
}
// panic: assignment to entry in nil map
To create maps with key-value pairs, we need to initialize them as well.
<map_name> := map[<key_data_type>]<value_data_type>{<key-value-pairs>}
codes :map[string]string{“en“: “english“, “fr”: “french”}
Creating and initializing a map
func main() {
// Declare and initialize the map with key-value pairs
codes := map[string]string{
"en": "english",
"fr": "french",
}
// Print the map
fmt.Println(codes)
}
//Output: map[en:english fr:french]
Declaring, and initializing a map using make()
function
<map_name> := make(map[<key_data_type>]<value_data_type>, <initial_capacity>)
- Capacity over here is an optional argument
func main() {
// Initialize an empty map
codes := make(map[string]int)
// Print the map
fmt.Println(codes)
}
// map[] >> Empty map
Length of a map len()
- To determine how many items or key-value pairs a map has.
func main() {
// Initialize the map with key-value pairs
codes := map[string]string{"en": "english", "fr": "french", "hi": "hindi"}
// Print the length of the map
fmt.Println(len(codes))
}
// Output: 3
Accessing a map
func main() {
// Initialize the map with key-value pairs
codes := map[string]string{
"en": "english",
"fr": "french",
"hi": "hindi",
}
// Print the values associated with each key
fmt.Println(codes["en"])
fmt.Println(codes["fr"])
fmt.Println(codes["hi"])
}
/*
english
french
hindi
*/
Getting a key
Getting a key in maps » getting the value associated with that key
value, found := map_name[key]
value » is the value of that key
found » it is optional, is a boolean, indicates if the key exist or not.
func main() {
// Initialize the map with key-value pairs
codes := map[string]int{
"en": 1,
"fr": 2,
"hi": 3,
}
// Check for the presence of the key "en"
value, found := codes["en"]
fmt.Println(found, value)
// Check for the presence of the key "hh"
value, found = codes["hh"]
fmt.Println(found, value)
}
/*
true 1
false 0
*/
Adding key-value pairs
func main() {
// Initialize the map with key-value pairs
codes := map[string]string{"en": "english", "fr": "french", "hi": "hindi"}
// Add a new key-value pair
codes["it"] = "italian"
// Print the map
fmt.Println(codes)
}
// Output: map[en:english fr:french hi:hindi it:italian]
Update key-value pairs
Overriding the existing value
func main() {
// Initialize the map with key-value pairs
codes := map[string]string{"en": "english", "fr": "french", "hi": "hindi"}
// Update the value for the key "en"
codes["en"] = "english langauge"
// Print the map
fmt.Println(codes)
}
// Output: map[en:english language fr:french hi:hindi]
Delete key-value pairs
- delete(map, key_name) » Takes
Map name
, andkey_name
as input
func main() {
// Initialize the map with key-value pairs
codes := map[string]string{"en": "english", "fr": "french", "hi": "hindi"}
// Print the map before deletion
fmt.Println(codes)
// Delete the key "en"
delete(codes, "en")
// Print the map after deletion
fmt.Println(codes)
}
/*
map[en:english fr:french hi:hindi]
map[fr:french hi:hindi]
*/
Iterate over a map using range
In array
range
returnsindex
andvalue
In slice
range
returnskey
andvalue
func main() {
// Initialize the map with key-value pairs
codes := map[string]string{"en": "english", "fr": "french", "hi": "hindi"}
// Iterate over the map and print each key-value pair
for key, value := range codes {
fmt.Println(key, "->", value)
}
}
/*
en -> english
fr -> french
hi -> hindi
*/
Truncate a map
- Deleting/clearing all elements
Iterating over the map and deleting one by one
func main() {
// Initialize the map with key-value pairs
codes := map[string]string{"en": "english", "fr": "french", "hi": "hindi"}
// Iterate over the map and delete each key-value pair
for key := range codes {
delete(codes, key)
}
// Print the map after deletion
fmt.Println(codes)
}
// Output: map[]
Reinitializing the map with an empty map
func main() {
// Initialize the map with key-value pairs
codes := map[string]string{
"en": "english",
"fr": "french",
"hi": "hindi",
}
// Reinitialize the map to an empty map
codes = make(map[string]string)
// Print the map after reinitialization
fmt.Println(codes)
}
// Output: map[]
References
Subscribe to my newsletter
Read articles from Arindam Baidya directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by
