Go 解題 Package (ft. 106年技藝競賽)

tags: Go Package
category: Programming
description: Go 解題 Package (ft. 106年技藝競賽)
created_at: 2021/08/11 13:00:00
set: 技藝競賽

cover image


Source

Github: https://github.com/LaiJunBin/go-solve-kit

上面有比較詳細的文件


前言

Go 滿多東西都得自己實作的,解題起來就覺得有一點冗長,想說實現一些東西讓他寫起來更像 JavaScript 或是 VB LINQ,而做了這個 Package

在以前技藝競賽的時候規定使用 VB ,所以當時那種語法寫習慣了也覺得很方便,在PHP好像叫做流暢的介面(?),當時我是106年的,所以就拿106年的題目開刀吧,不然光做沒拿來用感覺也怪怪的,畢竟要做了才知道哪裡有不足需要加功能


安裝

$ go get github.com/laijunbin/go-solve-kit

引入

import (
    sk "github.com/laijunbin/go-solve-kit"
)

看看幾個範例

Example 1: 從標準輸入讀取兩個數並加總

func main() {
    sum := sk.LineInput().Split(" ")[:2].ToIntArray().Sum()
    fmt.Println(sum)
}

Example 2: 沒有要幹嘛,就是產生1~5的數字全部平方然後過濾留下偶數

func main() {
    nums := []int {1, 2, 3, 4, 5}
    output := sk.FromIntArray(nums).Map(func(v sk.Int, _ int) interface{} {
        return v * v
    }).Filter(func(v sk.Type, _ int) bool {
        return v.ToInt() % 2 == 0
    }).ToStringArray().Join("\n")
    fmt.Println(output)
}

輸出:

4
16

Example 3: 還是沒有要幹嘛,而且不太好形容

func main() {
    array2D := sk.NewArray(5).Map(func(_ sk.Type, i int) interface{} {
        return sk.NewRange(1, 5, 2).Map(func(v sk.Int, j int) interface{} {
            return v.ValueOf() * i
        })
    })
    fmt.Println(array2D)
    fmt.Println(array2D.Get(2, 2).ToInt())
    fmt.Println(array2D.Get(4, 1).ToInt())
    fmt.Println("-------------------")
    fmt.Println(array2D)
    fmt.Println(array2D.Length())
    fmt.Println(array2D.Flatten())
    fmt.Println(array2D.Flatten().Length())
}

輸出:

[{[{0} {0} {0}]} {[{1} {3} {5}]} {[{2} {6} {10}]} {[{3} {9} {15}]} {[{4} {12} {20}]}]
10
12
-------------------
[{[{0} {0} {0}]} {[{1} {3} {5}]} {[{2} {6} {10}]} {[{3} {9} {15}]} {[{4} {12} {20}]}]
5
[{0} {0} {0} {1} {3} {5} {2} {6} {10} {3} {9} {15} {4} {12} {20}]
15

開始解技藝競賽的題目


第一題: 計算含有 s 或 S 字母的字數

func main() {
    sk.NewArray(sk.LineInput().ToInt().ValueOf()).ForEach(func(_ sk.Type, _ int) {
        count := sk.LineInput().Split(" ").Filter(func(s sk.String, _ int) bool {
            return s.ToLower().Contains("s")
        }).Length()
        fmt.Println(count)
    })
}

第二題: 給一個羅馬數字符號,轉為整數數字

func main() {
    keys := sk.FromStringArray([]string {"I", "V", "X", "L", "C", "D", "M"})
    values:= sk.FromIntArray([]int {1, 5, 10, 50, 100, 500, 1000})
    sk.NewArray(sk.LineInput().ToInt().ValueOf()).ForEach(func(_ sk.Type, _ int) {
        val := 0
        data := sk.LineInput().TrimSpace().Split("")
        data.ForEach(func(s sk.String, i int) {
            if i == data.Length().ValueOf() - 1 {
                val += values[keys.IndexOf(s.ValueOf())].ValueOf()
            } else {
                currentIndex := keys.IndexOf(s.ValueOf())
                nextIndex := keys.IndexOf(data[i+1].ValueOf())
                sign := sk.If(currentIndex < nextIndex, -1, 1).(int)
                val += values[currentIndex].ValueOf() * sign
            }
        })
        fmt.Println(val)
    })
}

第三題: 信用卡卡號

func main() {
    sk.NewArray(sk.LineInput().ToInt().ValueOf()).ForEach(func(_ sk.Type, _ int) {
        sum := sk.LineInput()[:16].Split("").ToIntArray().Map(func(v sk.Int, i int) interface{} {
            val := v.ValueOf()
            n := sk.If(i % 2 == 0, 2, 1).(int)
            return sk.If(val * n >= 10, val * n - 9, val * n)
        }).ToIntArray().Sum()

        isValid := sk.If(sum % 10 == 0, "T", "F")
        fmt.Println(isValid)
    })
}

第四題: 幾 A 幾 B

func GetNumbers(nums sk.StringArray, current string) sk.TypeArray{
    if nums.Length() == 0 {
        return sk.NewArray(1).Fill(current)
    }

    return nums.Map(func(s sk.String, i int) interface{} {
        return GetNumbers(nums.Filter(func(_ sk.String, j int) bool {
            return i != j
        }), current + s.ValueOf())
    }).Flatten()
}

func main() {
    sk.NewArray(sk.LineInput().ToInt().ValueOf()).ForEach(func(_ sk.Type, _ int) {
        data := sk.LineInput().Split(",")
        nums, i, j := data[0].Split(""), data[1].ToInt() - 1, data[2].ToInt() - 1
        numbers := GetNumbers(nums, "").ToStringArray()
        num1, num2 := numbers[i], numbers[j]
        A, B := 0, 0

        num1.Split("").ForEach(func(s sk.String, i int) {
            index := num2.IndexOf(s.ValueOf())
            if i == index.ValueOf() {
                A += 1
            } else {
                B += 1
            }
        })

        fmt.Println(fmt.Sprintf("%vA%vB", A, B))
    })
}

第五題: 網段廣播位址

func main() {
    sk.NewArray(sk.LineInput().ToInt().ValueOf()).ForEach(func(_ sk.Type, _ int) {
        data := sk.LineInput().Split("/").Map(func(s sk.String, _ int) interface{} {
            return s.Split(".").ToIntArray()
        })
        ip, mask := data[0].ToIntArray(), data[1].ToIntArray()
        output := ip.Map(func(v sk.Int, i int) interface{} {
            return v | (255 - mask[i])
        }).ToStringArray().Join(".")
        fmt.Println(output)
    })
}

第六題: 大數排序問題

func main() {
    sk.NewArray(sk.LineInput().ToInt().ValueOf()).ForEach(func(_ sk.Type, _ int) {
        nums := sk.LineInput().Split(", ")
        sortedNums := nums.Copy()
        sortedNums.SortBy(func(x, y sk.String) bool {
            if x.Length() == y.Length() {
                return x.Split("").Some(func(_ sk.String, i int) bool {
                    return x[i] < y[i]
                })
            }

            return x.Length() < y.Length()
        })

        indexes := nums.Map(func(num sk.String, _ int) interface{} {
            return sortedNums.IndexOf(num.ValueOf()) + 1
        }).ToStringArray().Join(", ")
        fmt.Println(indexes)
    })
}

第七題: 樹

func Dfs(graph map[sk.Int]sk.IntArray, visited map[sk.Int]struct{}, node sk.Int, paths sk.IntArray) sk.IntArray {
    if paths.Contains(node.ValueOf()) {
        if paths.Slice(0, -2).Contains(node.ValueOf()) {
            return paths[paths.IndexOf(node.ValueOf()):]
        }
        return sk.IntArray{}
    }
    visited[node] = struct{}{}

    for _, nextNode := range graph[node] {
        if result := Dfs(graph, visited, nextNode, append(paths, node)); result.Length() > 0 {
            return result
        }
    }

    return sk.IntArray{}
}

func GetCycleNodes(graph map[sk.Int]sk.IntArray) sk.IntArray {
    visited := make(map[sk.Int]struct{}, 0)
    for node := range graph {
        if _, visit := visited[node]; visit {
            continue
        }
        if result := Dfs(graph, visited, node, sk.IntArray{}); result.Length() > 0 {
            return result
        }
    }

    return sk.IntArray{}
}

func main() {
    sk.NewArray(sk.LineInput().ToInt().ValueOf()).ForEach(func(_ sk.Type, _ int) {
        edges := sk.LineInput().Split(" ")
        graph := make(map[sk.Int]sk.IntArray, 0)
        edges.ForEach(func(s sk.String, _ int) {
            edge := s.Split(",").ToIntArray()
            if _, ok := graph[edge[0]]; !ok {
                graph[edge[0]] = sk.IntArray{}
            }
            if _, ok := graph[edge[1]]; !ok {
                graph[edge[1]] = sk.IntArray{}
            }

            graph[edge[0]] = append(graph[edge[0]], edge[1])
            graph[edge[1]] = append(graph[edge[1]], edge[0])
        })

        cycleNodes := GetCycleNodes(graph)
        cycleNodes.Sort()

        if cycleNodes.Length() > 0 {
            fmt.Println(cycleNodes.ToStringArray().Join(", "))
        } else {
            fmt.Println(sk.If(edges.Length().ValueOf() + 1 == len(graph), "T", "F"))
        }
    })
}

第八題: 後序運算式(postfix)

func main() {
    operators := sk.FromStringArray([]string {"+", "-", "*", "/"})
    sk.NewArray(sk.LineInput().ToInt().ValueOf()).ForEach(func(_ sk.Type, _ int) {
        expression := sk.LineInput().Split(" ")
        stack := sk.IntArray{}

        for i := 0; i < expression.Length().ValueOf(); i++ {
            if operators.Contains(expression[i].ValueOf()) {
                b := stack.Pop()
                a := stack.Pop()

                switch expression[i].ValueOf() {
                    case "+":
                        stack.Append((a + b).ValueOf())
                        break
                    case "-":
                        stack.Append((a - b).ValueOf())
                        break
                    case "*":
                        stack.Append((a * b).ValueOf())
                        break
                    case "/":
                        stack.Append((a / b).ValueOf())
                        break
                }
            } else {
                stack.Append(expression[i].ToInt().ValueOf())
            }
        }
        fmt.Println(stack.Pop())
    })
}

總結

雖然這些題目沒有特別難,但是如果以原生的 Go 下去解的話應該都會長滿多的,或是顯得雜亂一些,使用這一包 Package 來做程式碼就相對優美了一些。雖然也有可能是每個人習慣不同

目前還沒有做 Map 型別的包裝,但是可以像是第七題那樣自己稍微包一下,還是可以正常使用。




最後更新時間: 2021年08月11日.