add: more exercises to funcs
This commit is contained in:
@ -24,6 +24,4 @@ Let's exercise with the scanner and maps.
|
|||||||
|
|
||||||
6. **[Create the Log Parser program from scratch](https://github.com/inancgumus/learngo/tree/master/23-input-scanning/exercises/06-log-parser)**
|
6. **[Create the Log Parser program from scratch](https://github.com/inancgumus/learngo/tree/master/23-input-scanning/exercises/06-log-parser)**
|
||||||
|
|
||||||
You've watched the lecture. Now, try to create the same log parser program on your own. Do not look at the lecture, and the existing source code.
|
You've watched the lecture. Now, try to create the same log parser program on your own. Do not look at the lecture, and the existing source code. The link contains the code where you need to start working on.
|
||||||
|
|
||||||
Click the link for more details.
|
|
@ -7,3 +7,11 @@
|
|||||||
2. **[Refactor the Game Store to Funcs - Step #2](https://github.com/inancgumus/learngo/tree/master/25-functions/exercises/refactor-to-funcs-2)**
|
2. **[Refactor the Game Store to Funcs - Step #2](https://github.com/inancgumus/learngo/tree/master/25-functions/exercises/refactor-to-funcs-2)**
|
||||||
|
|
||||||
Let's continue the refactoring from the previous exercise. This time, you're going to refactor the command handling logic.
|
Let's continue the refactoring from the previous exercise. This time, you're going to refactor the command handling logic.
|
||||||
|
|
||||||
|
3. **[Refactor the Game Store to Funcs - Step #3](https://github.com/inancgumus/learngo/tree/master/25-functions/exercises/refactor-to-funcs-3)**
|
||||||
|
|
||||||
|
Let's continue from the previous exercise. This time, you're going to add json encoding and decoding using funcs.
|
||||||
|
|
||||||
|
4. **[Rewrite the Log Parser program using funcs](https://github.com/inancgumus/learngo/tree/master/25-functions/exercises/rewrite-log-parser-using-funcs)**
|
||||||
|
|
||||||
|
You've watched the lecture. Now, try to rewrite the same log parser program using funcs on your own.
|
70
25-functions/exercises/refactor-to-funcs-3/commands.go
Normal file
70
25-functions/exercises/refactor-to-funcs-3/commands.go
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
// 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"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
func runCmd(input string, games []game, byID map[int]game) bool {
|
||||||
|
fmt.Println()
|
||||||
|
|
||||||
|
cmd := strings.Fields(input)
|
||||||
|
if len(cmd) == 0 {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
switch cmd[0] {
|
||||||
|
case "quit":
|
||||||
|
return cmdQuit()
|
||||||
|
|
||||||
|
case "list":
|
||||||
|
return cmdList(games)
|
||||||
|
|
||||||
|
case "id":
|
||||||
|
return cmdByID(cmd, games, byID)
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func cmdQuit() bool {
|
||||||
|
fmt.Println("bye!")
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func cmdList(games []game) bool {
|
||||||
|
for _, g := range games {
|
||||||
|
printGame(g)
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func cmdByID(cmd []string, games []game, byID map[int]game) bool {
|
||||||
|
if len(cmd) != 2 {
|
||||||
|
fmt.Println("wrong id")
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
id, err := strconv.Atoi(cmd[1])
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println("wrong id")
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
g, ok := byID[id]
|
||||||
|
if !ok {
|
||||||
|
fmt.Println("sorry. i don't have the game")
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
printGame(g)
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
74
25-functions/exercises/refactor-to-funcs-3/games.go
Normal file
74
25-functions/exercises/refactor-to-funcs-3/games.go
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
// 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"
|
||||||
|
|
||||||
|
const data = `
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"id": 1,
|
||||||
|
"name": "god of war",
|
||||||
|
"genre": "action adventure",
|
||||||
|
"price": 50
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 2,
|
||||||
|
"name": "x-com 2",
|
||||||
|
"genre": "strategy",
|
||||||
|
"price": 40
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 3,
|
||||||
|
"name": "minecraft",
|
||||||
|
"genre": "sandbox",
|
||||||
|
"price": 20
|
||||||
|
}
|
||||||
|
]`
|
||||||
|
|
||||||
|
type item struct {
|
||||||
|
id int
|
||||||
|
name string
|
||||||
|
price int
|
||||||
|
}
|
||||||
|
|
||||||
|
type game struct {
|
||||||
|
item
|
||||||
|
genre string
|
||||||
|
}
|
||||||
|
|
||||||
|
func load() (games []game) {
|
||||||
|
games = addGame(games, newGame(1, 50, "god of war", "action adventure"))
|
||||||
|
games = addGame(games, newGame(2, 40, "x-com 2", "strategy"))
|
||||||
|
games = addGame(games, newGame(3, 20, "minecraft", "sandbox"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func addGame(games []game, g game) []game {
|
||||||
|
return append(games, g)
|
||||||
|
}
|
||||||
|
|
||||||
|
func newGame(id, price int, name, genre string) game {
|
||||||
|
return game{
|
||||||
|
item: item{id: id, name: name, price: price},
|
||||||
|
genre: genre,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func indexByID(games []game) (byID map[int]game) {
|
||||||
|
byID = make(map[int]game)
|
||||||
|
for _, g := range games {
|
||||||
|
byID[g.id] = g
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func printGame(g game) {
|
||||||
|
fmt.Printf("#%d: %-15q %-20s $%d\n",
|
||||||
|
g.id, g.name, "("+g.genre+")", g.price)
|
||||||
|
}
|
61
25-functions/exercises/refactor-to-funcs-3/main.go
Normal file
61
25-functions/exercises/refactor-to-funcs-3/main.go
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
// 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/
|
||||||
|
//
|
||||||
|
|
||||||
|
// ---------------------------------------------------------
|
||||||
|
// EXERCISE: Refactor the game store to funcs - step #3
|
||||||
|
//
|
||||||
|
// Let's continue from the previous exercise. This time,
|
||||||
|
// you're going to add json encoding and decoding using
|
||||||
|
// funcs.
|
||||||
|
//
|
||||||
|
// 1- Create a new command in a func that encodes the
|
||||||
|
// game store data to json and terminates the program.
|
||||||
|
// Lastly, add it to runCmd func.
|
||||||
|
//
|
||||||
|
// For more information, see: "Encode" exercise from
|
||||||
|
// the structs section.
|
||||||
|
//
|
||||||
|
// Name : cmdSave
|
||||||
|
// Inputs: []game
|
||||||
|
// Output: bool
|
||||||
|
//
|
||||||
|
// 2- Refactor the load() to load the games from the
|
||||||
|
// `data` constant (it's in the games.go as well).
|
||||||
|
//
|
||||||
|
// For more information, see: "Decode" exercise from
|
||||||
|
// the structs section.
|
||||||
|
//
|
||||||
|
// ---------------------------------------------------------
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
games := load()
|
||||||
|
byID := indexByID(games)
|
||||||
|
|
||||||
|
fmt.Printf("Inanc's game store has %d games.\n", len(games))
|
||||||
|
|
||||||
|
in := bufio.NewScanner(os.Stdin)
|
||||||
|
for {
|
||||||
|
fmt.Printf(`
|
||||||
|
> list : lists all the games
|
||||||
|
> id N : queries a game by id
|
||||||
|
> quit : quits
|
||||||
|
|
||||||
|
`)
|
||||||
|
|
||||||
|
if !in.Scan() || !runCmd(in.Text(), games, byID) {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,91 @@
|
|||||||
|
// 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 (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
func runCmd(input string, games []game, byID map[int]game) bool {
|
||||||
|
fmt.Println()
|
||||||
|
|
||||||
|
cmd := strings.Fields(input)
|
||||||
|
if len(cmd) == 0 {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
switch cmd[0] {
|
||||||
|
case "quit":
|
||||||
|
return cmdQuit()
|
||||||
|
|
||||||
|
case "list":
|
||||||
|
return cmdList(games)
|
||||||
|
|
||||||
|
case "id":
|
||||||
|
return cmdByID(cmd, games, byID)
|
||||||
|
|
||||||
|
case "save":
|
||||||
|
return cmdSave(games)
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func cmdQuit() bool {
|
||||||
|
fmt.Println("bye!")
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func cmdList(games []game) bool {
|
||||||
|
for _, g := range games {
|
||||||
|
printGame(g)
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func cmdByID(cmd []string, games []game, byID map[int]game) bool {
|
||||||
|
if len(cmd) != 2 {
|
||||||
|
fmt.Println("wrong id")
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
id, err := strconv.Atoi(cmd[1])
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println("wrong id")
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
g, ok := byID[id]
|
||||||
|
if !ok {
|
||||||
|
fmt.Println("sorry. i don't have the game")
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
printGame(g)
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func cmdSave(games []game) bool {
|
||||||
|
// load the data into encodable game values
|
||||||
|
var jg []jsonGame
|
||||||
|
for _, g := range games {
|
||||||
|
jg = append(jg, jsonGame{g.id, g.name, g.genre, g.price})
|
||||||
|
}
|
||||||
|
|
||||||
|
out, err := json.MarshalIndent(jg, "", "\t")
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println("sorry, can't save:", err)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println(string(out))
|
||||||
|
return false
|
||||||
|
}
|
93
25-functions/exercises/refactor-to-funcs-3/solution/games.go
Normal file
93
25-functions/exercises/refactor-to-funcs-3/solution/games.go
Normal file
@ -0,0 +1,93 @@
|
|||||||
|
// 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 (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
)
|
||||||
|
|
||||||
|
const data = `
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"id": 1,
|
||||||
|
"name": "god of war",
|
||||||
|
"genre": "action adventure",
|
||||||
|
"price": 50
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 2,
|
||||||
|
"name": "x-com 2",
|
||||||
|
"genre": "strategy",
|
||||||
|
"price": 40
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 3,
|
||||||
|
"name": "minecraft",
|
||||||
|
"genre": "sandbox",
|
||||||
|
"price": 20
|
||||||
|
}
|
||||||
|
]`
|
||||||
|
|
||||||
|
type item struct {
|
||||||
|
id int
|
||||||
|
name string
|
||||||
|
price int
|
||||||
|
}
|
||||||
|
|
||||||
|
type game struct {
|
||||||
|
item
|
||||||
|
genre string
|
||||||
|
}
|
||||||
|
|
||||||
|
// encodable and decodable game type
|
||||||
|
type jsonGame struct {
|
||||||
|
ID int `json:"id"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
Genre string `json:"genre"`
|
||||||
|
Price int `json:"price"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func load() (games []game) {
|
||||||
|
// load the initial data from json
|
||||||
|
var decoded []jsonGame
|
||||||
|
if err := json.Unmarshal([]byte(data), &decoded); err != nil {
|
||||||
|
fmt.Println("Sorry, there is a problem:", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// load the data into usual game values
|
||||||
|
for _, dg := range decoded {
|
||||||
|
games = addGame(games, newGame(dg.ID, dg.Price, dg.Name, dg.Genre))
|
||||||
|
}
|
||||||
|
return games
|
||||||
|
}
|
||||||
|
|
||||||
|
func addGame(games []game, g game) []game {
|
||||||
|
return append(games, g)
|
||||||
|
}
|
||||||
|
|
||||||
|
func newGame(id, price int, name, genre string) game {
|
||||||
|
return game{
|
||||||
|
item: item{id: id, name: name, price: price},
|
||||||
|
genre: genre,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func indexByID(games []game) (byID map[int]game) {
|
||||||
|
byID = make(map[int]game)
|
||||||
|
for _, g := range games {
|
||||||
|
byID[g.id] = g
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func printGame(g game) {
|
||||||
|
fmt.Printf("#%d: %-15q %-20s $%d\n",
|
||||||
|
g.id, g.name, "("+g.genre+")", g.price)
|
||||||
|
}
|
36
25-functions/exercises/refactor-to-funcs-3/solution/main.go
Normal file
36
25-functions/exercises/refactor-to-funcs-3/solution/main.go
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
// 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 (
|
||||||
|
"bufio"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
games := load()
|
||||||
|
byID := indexByID(games)
|
||||||
|
|
||||||
|
fmt.Printf("Inanc's game store has %d games.\n", len(games))
|
||||||
|
|
||||||
|
in := bufio.NewScanner(os.Stdin)
|
||||||
|
for {
|
||||||
|
fmt.Printf(`
|
||||||
|
> list : lists all the games
|
||||||
|
> id N : queries a game by id
|
||||||
|
> save : exports the data to json and quits
|
||||||
|
> quit : quits
|
||||||
|
|
||||||
|
`)
|
||||||
|
|
||||||
|
if !in.Scan() || !runCmd(in.Text(), games, byID) {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,6 @@
|
|||||||
|
learngoprogramming.com 10
|
||||||
|
learngoprogramming.com 10
|
||||||
|
golang.org 4
|
||||||
|
golang.org 6
|
||||||
|
blog.golang.org 20
|
||||||
|
blog.golang.org 10
|
@ -0,0 +1,6 @@
|
|||||||
|
learngoprogramming.com 10
|
||||||
|
learngoprogramming.com 10
|
||||||
|
golang.org
|
||||||
|
golang.org 6
|
||||||
|
blog.golang.org 20
|
||||||
|
blog.golang.org 10
|
@ -0,0 +1,6 @@
|
|||||||
|
learngoprogramming.com 10
|
||||||
|
learngoprogramming.com 10
|
||||||
|
golang.org -100
|
||||||
|
golang.org 6
|
||||||
|
blog.golang.org 20
|
||||||
|
blog.golang.org 10
|
@ -0,0 +1,6 @@
|
|||||||
|
learngoprogramming.com 10
|
||||||
|
learngoprogramming.com 10
|
||||||
|
golang.org FOUR
|
||||||
|
golang.org 6
|
||||||
|
blog.golang.org 20
|
||||||
|
blog.golang.org 10
|
@ -0,0 +1,94 @@
|
|||||||
|
// 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 (
|
||||||
|
"bufio"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"sort"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
// result stores the parsed result for a domain
|
||||||
|
type result struct {
|
||||||
|
domain string
|
||||||
|
visits int
|
||||||
|
// add more metrics if needed
|
||||||
|
}
|
||||||
|
|
||||||
|
// parser keep tracks of the parsing
|
||||||
|
type parser struct {
|
||||||
|
sum map[string]result // metrics per domain
|
||||||
|
domains []string // unique domain names
|
||||||
|
total int // total visits for all domains
|
||||||
|
lines int // number of parsed lines (for the error messages)
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
p := parser{sum: make(map[string]result)}
|
||||||
|
|
||||||
|
// Scan the standard-in line by line
|
||||||
|
in := bufio.NewScanner(os.Stdin)
|
||||||
|
for in.Scan() {
|
||||||
|
p.lines++
|
||||||
|
|
||||||
|
// Parse the fields
|
||||||
|
fields := strings.Fields(in.Text())
|
||||||
|
if len(fields) != 2 {
|
||||||
|
fmt.Printf("wrong input: %v (line #%d)\n", fields, p.lines)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
domain := fields[0]
|
||||||
|
|
||||||
|
// Sum the total visits per domain
|
||||||
|
visits, err := strconv.Atoi(fields[1])
|
||||||
|
if visits < 0 || err != nil {
|
||||||
|
fmt.Printf("wrong input: %q (line #%d)\n", fields[1], p.lines)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Collect the unique domains
|
||||||
|
if _, ok := p.sum[domain]; !ok {
|
||||||
|
p.domains = append(p.domains, domain)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Keep track of total and per domain visits
|
||||||
|
p.total += visits
|
||||||
|
|
||||||
|
// You cannot assign to composite values
|
||||||
|
// p.sum[domain].visits += visits
|
||||||
|
|
||||||
|
// create and assign a new copy of `visit`
|
||||||
|
p.sum[domain] = result{
|
||||||
|
domain: domain,
|
||||||
|
visits: visits + p.sum[domain].visits,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Print the visits per domain
|
||||||
|
sort.Strings(p.domains)
|
||||||
|
|
||||||
|
fmt.Printf("%-30s %10s\n", "DOMAIN", "VISITS")
|
||||||
|
fmt.Println(strings.Repeat("-", 45))
|
||||||
|
|
||||||
|
for _, domain := range p.domains {
|
||||||
|
parsed := p.sum[domain]
|
||||||
|
fmt.Printf("%-30s %10d\n", domain, parsed.visits)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Print the total visits for all domains
|
||||||
|
fmt.Printf("\n%-30s %10d\n", "TOTAL", p.total)
|
||||||
|
|
||||||
|
// Let's handle the error
|
||||||
|
if err := in.Err(); err != nil {
|
||||||
|
fmt.Println("> Err:", err)
|
||||||
|
}
|
||||||
|
}
|
Reference in New Issue
Block a user