GO: basic data type - slice

1, Limitations of arrays

 

Because the length of the array is fixed and the length of the array is part of the type, the array has many limitations. For example:

func arraySum(x [3]int) int{
    sum := 0
    for _, v := range x{
        sum = sum + v
    }
    return sum
}

This summation function can only accept [3]int type, and others are not supported. Another example:

a := [3]int{1, 2, 3}

There are already three elements in array A. We can't continue to add new elements to array a.

2, Slice

A slice is a variable length sequence of elements of the same type. It is a layer of encapsulation based on array types. It is very flexible and supports automatic capacity expansion.

A slice is a reference type whose internal structure contains address, length, and capacity. Slicing is generally used to quickly manipulate a data set.

2.1 definition of slice:

var name []T
  • Name: indicates variable name
  • T: Represents the element type in the slice
func main() {
	// Declare slice type
	var a []string              //Declare a string slice
	var b = []int{}             //Declare an integer slice and initialize it
	var c = []bool{false, true} //Declare a Boolean slice and initialize it
	var d = []bool{false, true} //Declare a Boolean slice and initialize it
	fmt.Println(a)              //[]
	fmt.Println(b)              //[]
	fmt.Println(c)              //[false true]
	fmt.Println(a == nil)       //true
	fmt.Println(b == nil)       //false
	fmt.Println(c == nil)       //false
	// fmt.Println(c == d) / / slice is a reference type. Direct comparison is not supported. It can only be compared with nil
}

Unlike arrays, there is no need to write the number of elements or infer [...] when declaring

2.2 slice length and capacity:

Slices have their own length and capacity. We can calculate the length by using the built-in len() function and the capacity by using the built-in cap() function.

2.3 slice expression:

Slice expressions construct substrings or slices from strings, arrays, and pointers to arrays or slices. It has two variants:

  • A simple form of specifying the low and high index bounds
  • The other is to specify the complete form of capacity in addition to the low and high index limit values.

Simple slice expression:

The bottom layer of the slice is an array, so we can get the slice through the slice expression based on the array. Low and high in the slice expression represent an index range (included on the left and not included on the right), that is, in the following code, select the elements with 1 < = index value < 4 from array a to form slice s, the obtained slice length = high low, and the capacity is equal to the capacity of the underlying array of the obtained slice.

func main() {
	a := [5]int{1, 2, 3, 4, 5}
	s := a[1:3]  // s := a[low:high]
	fmt.Printf("s:%v len(s):%v cap(s):%v\n", s, len(s), cap(s))
}

For convenience, any index in the slice expression can be omitted. If low is omitted, it defaults to 0; If high is omitted, it defaults to the length of the slice operand:

When a slice expression is performed on a slice again (slice again), the upper bound of high is the capacity cap(a) of the slice, not the length. The constant index must be non negative and can be represented by a value of type int; For arrays or constant strings, the constant index must also be within the valid range. If both low and high indicators are constants, they must meet low < = high. If the index is out of range at run time, a run-time panic occurs.

Full slice expression

For arrays, pointers to arrays, or slice a (note that it cannot be a string) support full slice expressions

a[low : high : max]

The above code will construct slices of the same type, length and element as the simple slice expression a[low: high]. In addition, it sets the capacity of the resulting slice to Max low. In the full slice expression, only the first index value (low) can be omitted; It defaults to 0.

The condition that the complete slice expression needs to meet is 0 < = low < = high < = max < = cap (a), and other conditions are the same as the simple slice expression.

3, Using the make function to construct slices

We create slices based on arrays above. If we need to create a slice dynamically, we need to use the built-in make() function. The format is as follows:

make([]T, size, cap)

Of which:

  • T: element type of slice
  • size: the number of elements in the slice
  • cap: capacity of slice
func main() {
	a := make([]int, 2, 10)
	fmt.Println(a)      //[0 0]
	fmt.Println(len(a)) //2
	fmt.Println(cap(a)) //10
}

In the above code, 10 internal storage spaces of a have been allocated, but actually only 2 have been allocated. The capacity does not affect the number of current elements, so len(a) returns 2 and cap(a) returns the capacity of the slice.

4, The essence of slicing

The essence of slicing is to encapsulate the underlying array, which contains three information:

  • Pointer to the underlying array
  • Length of slice (len)
  • Slice capacity (cap)

Determine whether the slice is empty:

To check whether the slice is empty, always use len(s) == 0 instead of s == nil.

5, Slice operation

Slices cannot be compared:

Slices cannot be compared. We cannot use the = = operator to judge whether two slices contain all equal elements. The only valid comparison of slices is with nil. A slice with nil value has no underlying array. The length and capacity of a slice with nil value are 0. But we can't say that a slice with length and capacity of 0 must be nil.

Assigned copy of slice:

The code of the surface demonstrates that the two variables before and after copying share the underlying array. The modification of one slice will affect the content of the other slice, which needs special attention.

func main() {
	s1 := make([]int, 3) //[0 0 0]
	s2 := s1             //Assign s1 directly to s2. s1 and s2 share a bottom array
	s2[0] = 100
	fmt.Println(s1) //[100 0 0]
	fmt.Println(s2) //[100 0 0]
}

Slice traversal:

The traversal mode of slices is consistent with that of arrays, and supports index traversal and for range traversal.

func main() {
	s := []int{1, 3, 5}

	for i := 0; i < len(s); i++ {
		fmt.Println(i, s[i])
	}

	for index, value := range s {
		fmt.Println(index, value)
	}
}

Slice add element:

The Go language's built-in function append() can dynamically add elements to slices. You can add one element at a time, multiple elements, or elements in another slice (followed by...).

func main(){
	var s []int
	s = append(s, 1)        // [1]
	s = append(s, 2, 3, 4)  // [1 2 3 4]
	s2 := []int{5, 6, 7}  
	s = append(s, s2...)    // [1 2 3 4 5 6 7]
}

Each slice will point to an underlying array. If the capacity of this array is enough, new elements will be added. When the underlying array cannot accommodate new elements, the slice will automatically "expand" according to certain strategies, and the underlying array pointed to by the slice will be replaced. The "capacity expansion" operation often occurs when the append() function is called, so we usually need to use the original variable to receive the return value of the append function.

Slice copy:

The copy() function built in Go language can quickly copy the data of one slice into another slice space. The format of copy() function is as follows:

copy(destSlice, srcSlice []T)

Of which:

  • srcSlice: data source slice
  • destSlice: target slice
func main() {
	// copy() copy slice
	a := []int{1, 2, 3, 4, 5}
	c := make([]int, 5, 5)
	copy(c, a)     //Use the copy() function to copy the elements in slice a to slice c
	fmt.Println(a) //[1 2 3 4 5]
	fmt.Println(c) //[1 2 3 4 5]
	c[0] = 1000
	fmt.Println(a) //[1 2 3 4 5]
	fmt.Println(c) //[1000 2 3 4 5]
}

Delete element from slice

There is no special method to delete slice elements in Go language. We can use the characteristics of slice itself to delete elements. The code is as follows:

func main() {
	// Delete element from slice
	a := []int{30, 31, 32, 33, 34, 35, 36, 37}
	// To delete an element with index 2
	a = append(a[:2], a[3:]...)
	fmt.Println(a) //[30 31 33 34 35 36 37]
}

To sum up, to delete the element with index from slice a, the operation method is a = append(a[:index], a[index+1:]...)

Keywords: Go Algorithm leetcode

Added by pablodelapena on Tue, 25 Jan 2022 09:26:25 +0200