diff --git a/16-slices/exercises/19-observe-len-cap/main.go b/16-slices/exercises/19-observe-len-cap/main.go new file mode 100644 index 0000000..85c99fe --- /dev/null +++ b/16-slices/exercises/19-observe-len-cap/main.go @@ -0,0 +1,109 @@ +package main + +import "fmt" + +// --------------------------------------------------------- +// EXERCISE: Observe the length and capacity +// +// Follow the instructions inside the code below to +// gain more intuition about the length and capacity of a slice. +// +// --------------------------------------------------------- + +func main() { + // --- #1 --- + // 1. create a new slice named: games + // + // 2. print the length and capacity of the games slice + // + // 3. comment out the games slice + // then declare it as an empty slice + // + // 4. print the length and capacity of the games slice + // + // 5. append the elements: "pacman", "mario", "tetris", "doom" + // + // 6. print the length and capacity of the games slice + // + // 7. comment out everything + // + // 8. declare it again using a slice literal + // (use the same elements from step 3) + + // --- #2 --- + // 1. use a loop from 0 to 4 to slice the games slice, element by element. + // + // 2. print its length and capacity along the way (in the loop). + + fmt.Println() + // for ... { + // fmt.Printf("games[:%d]'s len: %d cap: %d\n", ...) + // } + + // --- #3 --- + // 1. slice the games slice up to zero element + // (save the result to a new slice named: "zero") + // + // 2. print the games and the new slice's len and cap + // + // 3. append a new element to the new slice + // + // 4. print the new slice's lens and caps + // + // 5. repeat the last two steps 5 times (use a loop) + // + // 6. notice the growth of the capacity after the 5th append + // + // Use this slice's elements to append to the new slice: + // []string{"ultima", "dagger", "pong", "coldspot", "zetra"} + fmt.Println() + + // zero := ... + // fmt.Printf("games's len: %d cap: %d\n", ...) + // fmt.Printf("zero's len: %d cap: %d\n", ...) + + // for ... { + // ... + // fmt.Printf("zero's len: %d cap: %d\n", ...) + // } + + // --- #4 --- + // using a range loop, slice the zero slice element by element, + // and print its length and capacity along the way. + // + // observe that, the range loop only loops for the length, not the cap. + fmt.Println() + + // for ... { + // s := zero[:n] + // fmt.Printf("zero[:%d]'s len: %d cap: %d\n", ...) + // } + + // --- #5 --- + // 1. do the 3rd step above again but this time, start by slicing + // the zero slice up to its capacity (use the cap function). + // + // 2. print the elements of the zero slice in the loop. + fmt.Println() + + // zero = ... + // for ... { + // fmt.Printf("zero[:%d]'s len: %d cap: %d - %q\n", ...) + // } + + // --- #6 --- + // 1. change the one of the elements of the zero slice + // + // 2. change the same element of the games slice + // + // 3. print the games and the zero slices + // + // 4. observe that they don't have the same backing array + fmt.Println() + // ... + // fmt.Printf("zero : %q\n", zero) + // fmt.Printf("games : %q\n", games) + + // --- #7 --- + // try to slice the games slice beyond its capacity +} diff --git a/16-slices/exercises/19-observe-len-cap/solution/main.go b/16-slices/exercises/19-observe-len-cap/solution/main.go new file mode 100644 index 0000000..55d8175 --- /dev/null +++ b/16-slices/exercises/19-observe-len-cap/solution/main.go @@ -0,0 +1,76 @@ +// For more tutorials: https://blog.learngoprogramming.com +// +// Copyright © 2018 Inanc Gumus +// Learn Go Programming Course +// License: https://creativecommons.org/licenses/by-nc-sa/4.0/ +// + +package main + +import "fmt" + +func main() { + // --- #1 --- + // var games []string + // fmt.Printf("games's len : %d cap: %d\n", len(games), cap(games)) + + // games := []string{} + // fmt.Printf("games's len : %d cap: %d\n", len(games), cap(games)) + + // games = append(games, "pacman", "mario", "tetris", "doom") + // fmt.Printf("games's len : %d cap: %d\n", len(games), cap(games)) + + games := []string{"pacman", "mario", "tetris", "doom"} + fmt.Printf("games's len : %d cap: %d\n", len(games), cap(games)) + + // --- #2 --- + fmt.Println() + + for i := 0; i <= len(games); i++ { + s := games[:i] + fmt.Printf("games[:%d]'s len: %d cap: %d\n", i, len(s), cap(s)) + } + + // --- #3 --- + fmt.Println() + + zero := games[:0] + fmt.Printf("games's len: %d cap: %d\n", len(games), cap(games)) + fmt.Printf("zero's len: %d cap: %d\n", len(zero), cap(zero)) + + for _, v := range []string{"ultima", "dagger", "pong", "coldspot", "zetra"} { + zero = append(zero, v) + fmt.Printf("zero's len: %d cap: %d\n", len(zero), cap(zero)) + } + + // --- #4 --- + fmt.Println() + + for n := range zero { + s := zero[:n] + fmt.Printf("zero[:%d]'s len: %d cap: %d\n", n, len(s), cap(s)) + } + + // --- #5 --- + fmt.Println() + + zero = zero[:cap(zero)] + for n := range zero { + s := zero[:n] + fmt.Printf("zero[:%d]'s len: %d cap: %d - %q\n", n, len(s), cap(s), s) + } + + // --- #6 --- + fmt.Println() + + zero[0] = "command & conquer" + games[0] = "red alert" + fmt.Printf("zero : %q\n", zero) + fmt.Printf("games : %q\n", games) + + // --- #7 --- + // uncomment and see the error. + // _ = games[:cap(games)+1] + // or: + // _ = games[:5] +} diff --git a/16-slices/exercises/20-observe-the-cap-growth/main.go b/16-slices/exercises/20-observe-the-cap-growth/main.go new file mode 100644 index 0000000..3a5ecfb --- /dev/null +++ b/16-slices/exercises/20-observe-the-cap-growth/main.go @@ -0,0 +1,34 @@ +package main + +// --------------------------------------------------------- +// EXERCISE: Observe the capacity growth +// +// Write a program that loops 10 million times to append an element +// to a slice, on each step of the loop. Observe the capacity. +// +// +// STEPS +// +// 1. Create a nil slice +// +// 2. Loop 10e6 times +// +// 3. On each loop step: Append an element to the slice +// +// 4. Only print the length and capacity of the slice everytime +// the capacity changes. +// +// 5. Print also the growth rate by calculating the previous and +// the current capacity. +// +// +// EXPECTED OUTPUT +// +// len:0 cap:0 growth:NaN +// len:1 cap:1 growth:+Inf +// len:2 cap:2 growth:2.00 +// ... and so on. +// +// --------------------------------------------------------- + +func main() {} diff --git a/16-slices/exercises/20-observe-the-cap-growth/solution/main.go b/16-slices/exercises/20-observe-the-cap-growth/solution/main.go new file mode 100644 index 0000000..9a5aca4 --- /dev/null +++ b/16-slices/exercises/20-observe-the-cap-growth/solution/main.go @@ -0,0 +1,29 @@ +// For more tutorials: https://blog.learngoprogramming.com +// +// Copyright © 2018 Inanc Gumus +// Learn Go Programming Course +// License: https://creativecommons.org/licenses/by-nc-sa/4.0/ +// + +package main + +import "fmt" + +func main() { + var ( + nums []int + oldCap float64 + ) + + for len(nums) < 10e6 { + c := float64(cap(nums)) + + if c == 0 || c != oldCap { + fmt.Printf("len:%-15d cap:%-15g growth:%-15.2f\n", + len(nums), c, c/oldCap) + } + oldCap = c + + nums = append(nums, 1) + } +} diff --git a/16-slices/exercises/21-correct-the-lyric/main.go b/16-slices/exercises/21-correct-the-lyric/main.go new file mode 100644 index 0000000..2521ebd --- /dev/null +++ b/16-slices/exercises/21-correct-the-lyric/main.go @@ -0,0 +1,45 @@ +package main + +import ( + "fmt" + "strings" +) + +// --------------------------------------------------------- +// EXERCISE: Correct the lyric +// +// You have a slice of lyrics data of Beatles' awesome +// song: Yesterday. Your goal is putting the words into +// correct positions. +// +// +// STEPS +// +// 1. Prepend "yesterday" to the `lyric` slice. +// +// 2. Put the words to the correct position in the `lyric` slice. +// +// 3. Print the `lyric` slice. +// +// +// EXPECTED OUTPUT +// +// [yesterday all my troubles seemed so far away now it looks as though they are here to stay oh i believe in yesterday] +// +// +// BONUS +// +// . Think about when does the append allocates a new backing array. +// . Then check whether your conclusions are true or not. +// . You can use the prettyslice package to check the backing array. +// +// --------------------------------------------------------- + +func main() { + // DON'T TOUCH THIS: + lyric := strings.Fields(`all my troubles seemed so far away oh i believe in yesterday now it looks as though they are here to stay`) + + // ADD YOUR CODE BELOW: + // ... + fmt.Printf("%s\n", lyric) +} diff --git a/16-slices/exercises/21-correct-the-lyric/solution/main.go b/16-slices/exercises/21-correct-the-lyric/solution/main.go new file mode 100644 index 0000000..81dc924 --- /dev/null +++ b/16-slices/exercises/21-correct-the-lyric/solution/main.go @@ -0,0 +1,79 @@ +// For more tutorials: https://blog.learngoprogramming.com +// +// Copyright © 2018 Inanc Gumus +// Learn Go Programming Course +// License: https://creativecommons.org/licenses/by-nc-sa/4.0/ +// + +package main + +import ( + "fmt" + "strings" +) + +func main() { + // --- Correct Lyric --- + // yesterday all my troubles seemed so far away + // now it looks as though they are here to stay + // oh i believe in yesterday + + lyric := strings.Fields(`all my troubles seemed so far away oh i believe in yesterday now it looks as though they are here to stay`) + + // ------------------------------------------------------------------------ + // #1: Prepend "yesterday" to `lyric` + // ------------------------------------------------------------------------ + + // + // --- BEFORE --- + // all my troubles seemed so far away oh i believe in yesterday + // + // --- AFTER --- + // yesterday all my troubles seemed so far away oh i believe in yesterday + // + // (warning: allocates a new backing array) + // + lyric = append([]string{"yesterday"}, lyric...) + + // ------------------------------------------------------------------------ + // #2: Put the words to the correct position in the `lyric` slice. + // ------------------------------------------------------------------------ + + // + // yesterday all my troubles seemed so far away oh i believe in yesterday + // | | + // v v + // index: 8 pos: 13 + // + const N, M = 8, 13 + + // --- BEFORE --- + // + // yesterday all my troubles seemed so far away oh i believe in yesterday now it looks as though they are here to stay + // + // --- AFTER --- + // yesterday all my troubles seemed so far away oh i believe in yesterday now it looks as though they are here to stay oh i believe in yesterday + // ^ + // + // | + // +--- duplicate + // + // (warning: allocates a new backing array) + lyric = append(lyric, lyric[N:M]...) + + // + // --- BEFORE --- + // yesterday all my troubles seemed so far away oh i believe in yesterday now it looks as though they are here to stay oh i believe in yesterday + // + // --- AFTER --- + // yesterday all my troubles seemed so far away now it looks as though they are here to stay oh i believe in yesterday + // + // (does not allocate a new backing array because cap(lyric[:N]) > M) + // + lyric = append(lyric[:N], lyric[M:]...) + + // ------------------------------------------------------------------------ + // #3: Print + // ------------------------------------------------------------------------ + fmt.Printf("%s\n", lyric) +} diff --git a/16-slices/exercises/README.md b/16-slices/exercises/README.md index 60c573e..50abb57 100644 --- a/16-slices/exercises/README.md +++ b/16-slices/exercises/README.md @@ -52,3 +52,9 @@ These are warm-up exercises that will reinforce your knowledge of slices. 2. **[Sort the backing array](https://github.com/inancgumus/learngo/tree/master/16-slices/exercises/17-internals-backing-array-sort)** 3. **[Observe the memory allocations](https://github.com/inancgumus/learngo/tree/master/16-slices/exercises/18-internals-slice-header)** + +4. **[Observe the length and capacity](https://github.com/inancgumus/learngo/tree/master/16-slices/exercises/19-observe-len-cap)** + +5. **[Observe the capacity growth](https://github.com/inancgumus/learngo/tree/master/16-slices/exercises/20-observe-the-cap-growth)** + +6. **[Correct the lyric](https://github.com/inancgumus/learngo/tree/master/16-slices/exercises/21-correct-the-lyric)** \ No newline at end of file diff --git a/x-tba/slices/exercises/README.md b/x-tba/slices/exercises/README.md index bde330c..3cdf5ff 100644 --- a/x-tba/slices/exercises/README.md +++ b/x-tba/slices/exercises/README.md @@ -1,55 +1,68 @@ # Slice Exercises -## TODO -* internals - * shared array: implicit/explicit - * appending to a nil array - * sorts package sorting +--- - * exercises about capacity - * exercises about the mechanics of append - * growing - * adding elements at the middle etc - * exercises about full slice expressions +# ANNOUNCEMENT - * questions: - * slice header questions - * slice and ask what's the pointer field, len, cap etc - * when a new backing array is allocated: nil, empty, no capacity - * when to use a full slice expression +I teach you what the other courses don't even care to teach. +**What's new?** +* New Section: Advanced Slice Operations +* New Exercises for the Slice Internals +* New Exercises for the Slices: Advanced Operations + +**What are you going to learn?** +* Full Slice Expressions: Limiting access to the backing array +* Make(): Preallocation +* Copy(): Efficiently and safely copy elements without using a loop +* Multi-Dimensional Slices + +**What's coming next?** +* Empty Filer Finder: Your first taste of file operations. +* Bouncing Ball: Create a bouncing ball animation on a 2D surface. +* Png Parser: Parse a PNG file by hand and tell its dimensions. + +These lectures will be added in the next 3 weeks. + +**Statistics:** +* +1 hour of additional content! +* +5 new lectures +* +20 new questions +* 3 + ? new exercises + +**Total content in the slices section:** +* ? hours +* ? lectures +* ? questions +* ? exercises --- -## Exercises Level I - Basics +## Full Slice Exp + Make + Copy + Multi-Dim Slices -1. **[???](https://github.com/inancgumus/learngo/tree/master/16-slices/exercises/???)** +# FIX THIS +1. **[Limit the backing array sharing](https://github.com/inancgumus/learngo/tree/master/16-slices/exercises/??-limit-the-backing-array-sharing)** ---- -2. **[Get and Set Array Elements](https://github.com/inancgumus/learngo/tree/master/14-arrays/exercises/02-get-set-arrays)** +* fix the excess memory allocation + * return a huge slice from a func, ask the student fix it +* full slice exp: https://play.golang.org/p/SPrLspRBXdI +* copy: https://play.golang.org/p/SPrLspRBXdI + * + put \n for the beatles exercise using copy + ```go + s = append(s, 0 /* use the zero value of the element type */) + copy(s[i+1:], s[i:]) + s[i] = x + ``` -3. **[Refactor to Array Literals](https://github.com/inancgumus/learngo/tree/master/14-arrays/exercises/03-array-literal)** -4. **[Refactor to Ellipsis](https://github.com/inancgumus/learngo/tree/master/14-arrays/exercises/04-ellipsis)** +* multi dim slices batches +```go +actions := []int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9} +batchSize := 3 +var batches [][]int -5. **[Fix](https://github.com/inancgumus/learngo/tree/master/14-arrays/exercises/05-fix)** - -6. **[Compare the Arrays](https://github.com/inancgumus/learngo/tree/master/14-arrays/exercises/06-compare)** - -7. **[Assign the Arrays](https://github.com/inancgumus/learngo/tree/master/14-arrays/exercises/07-assign)** - ---- - -## Exercises Level II - -1. **[Wizard Printer](https://github.com/inancgumus/learngo/tree/master/14-arrays/exercises/08-wizard-printer)** - -2. **[Currency Converter](https://github.com/inancgumus/learngo/tree/master/14-arrays/exercises/09-currency-converter)** - -3. **[Hipster's Bookstore Search Engine](https://github.com/inancgumus/learngo/tree/master/14-arrays/exercises/10-hipsters-love-search)** - -4. **[Find the Average](https://github.com/inancgumus/learngo/tree/master/14-arrays/exercises/11-average)** - -5. **[Number Sorter](https://github.com/inancgumus/learngo/tree/master/14-arrays/exercises/12-sorter)** - -6. **[Word Finder](https://github.com/inancgumus/learngo/tree/master/14-arrays/exercises/13-word-finder)** +for batchSize < len(actions) { + actions, batches = actions[batchSize:], append(batches, actions[0:batchSize:batchSize]) +} +batches = append(batches, actions) +``` \ No newline at end of file diff --git a/x-tba/slices/exercises/_template/main.go b/x-tba/slices/exercises/_template/main.go new file mode 100644 index 0000000..f7bc9c3 --- /dev/null +++ b/x-tba/slices/exercises/_template/main.go @@ -0,0 +1,14 @@ +package main + +// --------------------------------------------------------- +// EXERCISE: ? +// +// +// +// EXPECTED OUTPUT +// +// +// --------------------------------------------------------- + +func main() { +} diff --git a/x-tba/slices/exercises/_template/solution/main.go b/x-tba/slices/exercises/_template/solution/main.go new file mode 100644 index 0000000..b5e729e --- /dev/null +++ b/x-tba/slices/exercises/_template/solution/main.go @@ -0,0 +1,11 @@ +// For more tutorials: https://blog.learngoprogramming.com +// +// Copyright © 2018 Inanc Gumus +// Learn Go Programming Course +// License: https://creativecommons.org/licenses/by-nc-sa/4.0/ +// + +package main + +func main() { +} diff --git a/x-tba/slices/exercises/fix-xx-limit-the-backing-array-sharing/api/api.go b/x-tba/slices/exercises/fix-xx-limit-the-backing-array-sharing/api/api.go new file mode 100644 index 0000000..97bba20 --- /dev/null +++ b/x-tba/slices/exercises/fix-xx-limit-the-backing-array-sharing/api/api.go @@ -0,0 +1,20 @@ +package api + +var temps = []int{5, 10, 3, 25, 45, 80, 90} + +// Read returns a range of temperature readings beginning from +// the `start` until to the `stop`. +func Read(start, stop int) []int { + // ---------------------------------------- + // RESTRICTIONS — ONLY ADD YOUR CODE HERE + + portion := temps[start:stop] + + // ---------------------------------------- + return portion +} + +// All returns all the temperature readings +func All() []int { + return temps +} diff --git a/x-tba/slices/exercises/fix-xx-limit-the-backing-array-sharing/main.go b/x-tba/slices/exercises/fix-xx-limit-the-backing-array-sharing/main.go new file mode 100644 index 0000000..e99522c --- /dev/null +++ b/x-tba/slices/exercises/fix-xx-limit-the-backing-array-sharing/main.go @@ -0,0 +1,73 @@ +// For more tutorials: https://blog.learngoprogramming.com +// +// Copyright © 2018 Inanc Gumus +// Learn Go Programming Course +// License: https://creativecommons.org/licenses/by-nc-sa/4.0/ +// + +package main + +import ( + "fmt" + + "github.com/inancgumus/learngo/16-slices/exercises/19-limit-the-backing-array-sharing/api" +) + +// --------------------------------------------------------- +// EXERCISE: Limit the backing array sharing +// +// You've created an API that returns population counts in a country. +// To do that, you return an int slice up to some portion of it. +// +// There is a program that uses your API but it appends to the slice +// that your API returns. Doing so, overwrites your API's slice's +// backing array as well. +// +// Change your API so that it prevents the overwriting when +// the client code wants to append to the returned slice from your +// API. +// +// +// STEPS +// +// 1. Open the code inside the `api/api.go` folder +// +// 2. Fix the code there (not here — but run this code after) +// +// +// CURRENT OUTPUT +// +// The following program overwrites the elements incorrectly +// You need to change your API to prevent this behavior +// ^ ^ +// | | +// API's readings: [5 10 3 1 3 80 90] +// Your readings : [5 10 3 1 3] +// +// +// EXPECTED OUTPUT +// +// Now the program cannot change the API's original backing array +// (beyond the returned capacity) (so the api now owns the control) +// ^ ^ +// | | +// API's readings: [5 10 3 25 45 80 90] +// Your readings : [5 10 3 1 3] +// +// --------------------------------------------------------- + +func main() { + // DO NOT TOUCH THE FOLLOWING CODE + // THIS IS THE CLIENT PROGRAM THAT USES YOUR API + // YOU CANNOT CONTROL IT! :) + + // reads the first three temperatures + temps := api.Read(0, 3) + + // appends two new temperature readings + temps = append(temps, []int{1, 3}...) + + // prints the current temperatures + fmt.Println("API's readings:", api.All()) + fmt.Println("Your readings :", temps) +} diff --git a/x-tba/slices/exercises/fix-xx-limit-the-backing-array-sharing/solution/api/api.go b/x-tba/slices/exercises/fix-xx-limit-the-backing-array-sharing/solution/api/api.go new file mode 100644 index 0000000..91ef119 --- /dev/null +++ b/x-tba/slices/exercises/fix-xx-limit-the-backing-array-sharing/solution/api/api.go @@ -0,0 +1,24 @@ +package api + +var temps = []int{5, 10, 3, 25, 45, 80, 90} + +// Read returns a range of temperature readings beginning from +// the `start` until to the `stop`. +func Read(start, stop int) []int { + // Uses a full slice expression to control the length of the + // backing array (or the capacity of the returned slice). + // + // So the next append allocates a new backing array, which + // in turn doesn't overwrite the temps slice's backing array. + // ^^ + // || + // / \ + // | | + portion := temps[start:stop:stop] + return portion +} + +// All returns all the temperature readings +func All() []int { + return temps +} diff --git a/x-tba/slices/exercises/fix-xx-limit-the-backing-array-sharing/solution/main.go b/x-tba/slices/exercises/fix-xx-limit-the-backing-array-sharing/solution/main.go new file mode 100644 index 0000000..1a9a645 --- /dev/null +++ b/x-tba/slices/exercises/fix-xx-limit-the-backing-array-sharing/solution/main.go @@ -0,0 +1,23 @@ +// For more tutorials: https://blog.learngoprogramming.com +// +// Copyright © 2018 Inanc Gumus +// Learn Go Programming Course +// License: https://creativecommons.org/licenses/by-nc-sa/4.0/ +// + +package main + +import ( + "fmt" + + "github.com/inancgumus/learngo/16-slices/exercises/19-limit-the-backing-array-sharing/solution/api" +) + +func main() { + temps := api.Read(0, 3) + + temps = append(temps, []int{1, 3}...) + + fmt.Println("API's readings:", api.All()) + fmt.Println("Your readings :", temps) +}