# array、slice、map
golang複合型別包括:陣列、切片、Maps、結構體。
## 陣列(Array)
陣列(Array)是一個固定空間(建立後不能改變長度)的容器,在同一個陣列裡的所有元素型態皆相同。
陣列中的元素可以透過索引(index)來操作,索引從 `0` 開始。
| 第一個元素 | 第二個元素 | 第三個元素 | 第四個元素 | 第五個元素 |
| -------- | -------- | -------- | -------- | -------- |
| arr[0] | arr[1] | arr[2] | arr[3] | arr[4]
### 宣告陣列
宣告長度為10 整數型態的陣列:
```go=
var arr [10]int // 使用var關鍵字宣告
arr := [10]int{} // 簡化宣告
```
Go語言宣告陣列時必須給定陣列大小以及型態。
```go=
var arr [10]int
arr[0] = 49
arr[1] = 55
fmt.Printf(arr[0]) // 49
fmt.Printf(arr[1]) // 55
fmt.Printf(arr[9]) // 未賦予值,預設為 0
```
### 陣列初始化
將等號擺在型態以及大小的左邊,並且使用 `{ }` 括住陣列元素,每個元素以 `,` 隔開。
```go=
var arr = [10]int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
arr2 := [10]int{10, 11, 12, 13, 14, 15, 16, 17, 18, 19}
```
當不知道這個陣列要多長時,可以使用 `[...]` 來讓 Go自行偵測你的陣列中有多少元素。
```go=
arr := [...]int{10, 11, 12, 13, 14}
len(arr) // len可用於獲取容器長度 , arr陣列的長度為 5
```
### 多維陣列
Go還支援巢狀陣列(多維陣列)
```go=
doubleArr := [2][3]int{{55, 56, 57}, {58, 59, 60}}
fmt.Println(doubleArr, len(doubleArr)) // 印出陣列為 [[55 56 57] [58 59 60]] 長度為 2
fmt.Println(doubleArr[0]) // 輸出二維陣列索引第0個元素為 [55,56,57]
fmt.Println(doubleArr[0][2]) // 輸出為第0個元素中的第2個元素 為 57
```
### 走訪陣列
因為還沒說到迴圈的部分,先簡單帶一下,或者有其他程式語言經驗的話應該就很好懂了。
Go語言的 for 迴圈語法為:
```go=
for i := 0 ; i < 10 ; i++ {
//code
}
```
使用迴圈走訪 arr 陣列並印出陣列中的所有值:
```go=
arr := [10]int{10, 11, 12, 13, 14, 15, 16, 17, 18, 19}
for i := 0; i < len(arr); i++ {
fmt.Print(arr[i], " ") //印出 10 11 12 13 14 15 16 17 18 19
}
```
for迴圈也可以簡化成下面的方式
index可以用 `_` 下划線取代,意即 blank identifier(啞變數),代表我不需要使用這個變數。而 number 才是陣列的值。
```go=
arr := [10]int{10, 11, 12, 13, 14, 15, 16, 17, 18, 19}
for index, number := range arr {
fmt.Print(fmt.Sprintf("%d : %d / ", index, number))
}
```
### 驗收
我在leetcode上找了一題難易度為easy的array題來試了一下,下面的code是我最先想到的寫法,但並不是很優,未來待我水平提高之後再回來重寫。
> **1480.Running Sum of 1d Array**
>
> Given an array nums. We define a running sum of an array as runningSum[i] = sum(nums[0]…nums[i]).
> Return the running sum of nums.
>
> **Example 1:**
>
> Input: nums = [1,2,3,4]
> Output: [1,3,6,10]
> Explanation: Running sum is obtained as follows: [1, 1+2, 1+2+3, 1+2+3+4].
>
> **Example 2:**
>
> Input: nums = [1,1,1,1,1]
> Output: [1,2,3,4,5]
> Explanation: Running sum is obtained as follows: [1, 1+1, 1+1+1, 1+1+1+1, 1+1+1+1+1].
>
> **Example 3:**
>
> Input: nums = [3,1,2,10,1]
> Output: [3,4,6,16,17]
>
> **Constraints:**
>
> 1 <= nums.length <= 1000
> -106 <= nums[i] <= 106
sol:
```go=
func runningSum(nums []int) []int {
var allsum int
output := []int{}
for i:=0 ; i<len(nums) ; i++{
allsum += nums[i]
output = append(output,allsum)
}
return output
}
```
## 切片(Slice)
Slice其實就是List,與Array不同的地方在於它的長度是可變的,而Array定義多長就是多長。
### 宣告切片
跟Array的宣告方式一樣,只差在切片不需要宣告長度
```go=
var slice1 []int //與宣告Array只差在沒有長度
```
也可以使用 `make()` 函數來創建切片(可給予長度)
```go=
var slice2 []int = make([]int,10)
// 簡寫為
slice2 := make([]int,10)
```
### 初始化切片
與Array相同,差別只在沒有給予長度。
```go=
slice := []int{1, 2, 3, 4, 5}
fmt.Print(slice) //[1 2 3 4 5]
```
使用 `slice[ i : j ]` 指定輸出這個切片索引 i ~ (j-1) 的元素,`slice[1:3]` 輸出為 [2 3]
`slice[i: ]` 代表創建從 i 元素開始直到最後一個元素的切片
`slice[ :j]` 代表創建從 0 直到 j-1 元素的切片
`slice[:]` 包含所有slice內的元素
```go=
slice := []int{1, 2, 3, 4, 5}
fmt.Print(slice[1:3]) // [2 3]
fmt.Print(slice[1:]) // [2 3 4 5]
fmt.Print(slice[:3]) // [1 2 3]
fmt.Print(slice[:]) // [1 2 3 4 5]
```
### 新增元素
可以使用 `append` 向切片裡追加一個至多個元素:
```go=
slice1 := []int{1, 2, 3, 4, 5}
fmt.Print(slice1[:]) // [1 2 3 4 5]
slice1 = append(slice1, 6, 7, 8, 9, 10)
fmt.Print(slice1[:]) // [1 2 3 4 5 6 7 8 9 10]
```
允許追加空切片,即 `append(slice1 , 0)`
Go中沒有移除元素的函式,但我們可以透過取索引時忽略該元素來達到移除該元素的目的。
```go=
slice1 = append(slice1[0:2], slice1[3:5]) //slice1[2] 被移除了
```
## 映射(Map)
Map是一種**無序**的鍵值對集合,map最重要的一點是通過 key 來快速檢索數據,類似陣列和切片的索引,指向數據的值。
### 定義方式
#### 第一種
首先定義一個Map變數,但值為空。我們需要通過 `make` 來開闢內部空間並做基本的賦值
```go=
var myMap map[string]string
//在使用map前需要先用make給map分配數據空間
myMap = make(map[string]string, 10)
myMap["name"] = "小明"
myMap["address"] = "台灣新北市"
myMap["phone"] = "0905123456"
fmt.Println(myMap) //map[address:台灣新北市 name:小明 phone:0905123456]
```
當**鍵值對不存在** 或者 **沒有初始化map** , 會回傳預設值`nil`
```go=
if myMap == nil{
fmt.Println("myMap是一個空map")
}
```
你會發現打印出來的順序並非按照程式碼所寫的順序,這是因為map是使用**雜湊函式(hash)**來實現的。
#### 第二種
直接通過 定義變數 `make` 創建map型別變數再去賦值。
```go=
myMap2 := make(map[int]string) //可以不用分配空間大小, 默認會分配一些
myMap2[1] = "小明"
myMap2[2] = "台灣新北市"
myMap2[3] = "0905123456"
fmt.Println(myMap2) //map[1:小明 2:台灣新北市 3:0905123456]
```
#### 第三種
在定義map的時候直接使用` { } `新增鍵值對初始化,在初始化過程時已經開闢了空間因此不需要使用`make`。
```go=
myMap3 := map[string] string{
"name": "小明",
"address": "台灣新北市",
"phone": "0905123456",
}
fmt.Println(myMap3) //map[address:台灣新北市 name:小明 phone:0905123456]
```
注意每一個鍵值對後方都要加上 `,` 包括最後一個鍵值對也是。
### 使用方式
#### 新增元素
使用 `mapName[key] = value` 新增元素
```go=
var myMap = make(map[string]string, 10)
myMap["name"] = "小明"
myMap["address"] = "台灣新北市"
myMap["phone"] = "0905123456"
fmt.Println(myMap) //map[address:台灣新北市 name:小明 phone:0905123456]
myMap2 := make(map[int]string)
myMap2[1] = "小明"
myMap2[2] = "台灣新北市"
myMap2[3] = "0905123456"
fmt.Println(myMap2) //map[1:小明 2:台灣新北市 3:0905123456]
myMap3 := map[string] string{
"name": "小明",
"address": "台灣新北市",
"phone": "0905123456",
}
myMap3["email"] = "pluto@gmail.com"
fmt.Println(myMap3) //map[address:台灣新北市 email:pluto@gmail.com name:小明 phone:0905123456]
```
#### 刪除元素
`delete(mapName, key)` 函數用於刪除集合的元素,參數為Map和其對應的key
```go=
myMap3 := map[string] string{
"name": "小明",
"address": "台灣新北市",
"phone": "0905123456",
}
delete(myMap, "address")
fmt.Println(myMap3)
```
#### 修改元素
與新增元素的方式一樣,差別只在key為想要修改的鍵值對的key
```go=
myMap3 := map[string]string{
"name": "小明",
"address": "台灣新北市",
"phone": "0905123456",
}
myMap3["name"] = "小王"
fmt.Println(myMap3) //map[address:台灣新北市 name:小王 phone:0905123456]
```
#### 走訪
可以用迭代器走訪映射:
```go=
myMap2 := make(map[string]string)
myMap2["name"] = "小明"
myMap2["address"] = "台灣新北市"
myMap2["phone"] = "0905123456"
//利用 rage 取得 map 中所有的 key 和 value, 並列印
for key, value := range myMap2 {
fmt.Println(fmt.Sprintf("%s: %s", key, value))
}
```
```go=
name: 小明
address: 台灣新北市
phone: 0905123456
```