# 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 ```