From 07182fad27af86f254612474932cc8fab49946db Mon Sep 17 00:00:00 2001 From: aqzholsky <98736657+aqzholsky@users.noreply.github.com> Date: Sun, 28 Jul 2024 20:21:15 +0500 Subject: [PATCH 01/17] initial commit --- exercise1/problem1/main.go | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/exercise1/problem1/main.go b/exercise1/problem1/main.go index dfca465c..e1a52439 100644 --- a/exercise1/problem1/main.go +++ b/exercise1/problem1/main.go @@ -1,3 +1,8 @@ package main -func addUp() {} +func addUp(n int) (sum int) { + for i := 0; i <= n; i++ { + sum += i + } + return +} From 92b3c04594abe4f64d9ec17364ad46bdc0826a05 Mon Sep 17 00:00:00 2001 From: aqzholsky <98736657+aqzholsky@users.noreply.github.com> Date: Mon, 29 Jul 2024 16:55:16 +0500 Subject: [PATCH 02/17] completed --- exercise1/problem10/main.go | 21 ++++++++++++++++++++- exercise1/problem2/main.go | 15 ++++++++++++++- exercise1/problem3/main.go | 8 +++++++- exercise1/problem4/main.go | 13 ++++++++++++- exercise1/problem5/main.go | 6 +++++- exercise1/problem6/main.go | 18 +++++++++++++++++- exercise1/problem7/main.go | 10 +++++++++- exercise1/problem8/main.go | 10 +++++++++- exercise1/problem9/main.go | 12 +++++++++--- 9 files changed, 102 insertions(+), 11 deletions(-) diff --git a/exercise1/problem10/main.go b/exercise1/problem10/main.go index 04ec3430..a707031d 100644 --- a/exercise1/problem10/main.go +++ b/exercise1/problem10/main.go @@ -1,3 +1,22 @@ package main -func sum() {} +import ( + "fmt" + "strconv" +) + +func sum(m, n string) (string, error) { + intM, err := strconv.Atoi(m) + if err != nil { + return "", fmt.Errorf("string: %s cannot be converted", m) + } + + intN, err := strconv.Atoi(n) + if err != nil { + return "", fmt.Errorf("string: %s cannot be converted", n) + } + + result := intM + intN + + return strconv.Itoa(result), nil +} diff --git a/exercise1/problem2/main.go b/exercise1/problem2/main.go index 2ca540b8..fe75619c 100644 --- a/exercise1/problem2/main.go +++ b/exercise1/problem2/main.go @@ -1,3 +1,16 @@ package main -func binary() {} +import "strconv" + +func binary(n int) (binaryStr string) { + if n == 0 { + return "0" + } + + for n > 0 { + binaryStr = strconv.Itoa(n%2) + binaryStr + n /= 2 + } + + return +} diff --git a/exercise1/problem3/main.go b/exercise1/problem3/main.go index d346641a..c7d52ff0 100644 --- a/exercise1/problem3/main.go +++ b/exercise1/problem3/main.go @@ -1,3 +1,9 @@ package main -func numberSquares() {} +func numberSquares(n int) int { + sum := 0 + for i := 1; i <= n; i++ { + sum += i * i + } + return sum +} diff --git a/exercise1/problem4/main.go b/exercise1/problem4/main.go index 74af9044..7a13f7da 100644 --- a/exercise1/problem4/main.go +++ b/exercise1/problem4/main.go @@ -1,3 +1,14 @@ package main -func detectWord() {} +import ( + "unicode" +) + +func detectWord(word string) (detectWord string) { + for _, char := range word { + if unicode.IsLower(char) { + detectWord += string(char) + } + } + return +} diff --git a/exercise1/problem5/main.go b/exercise1/problem5/main.go index c5a804c9..eb4cd0a6 100644 --- a/exercise1/problem5/main.go +++ b/exercise1/problem5/main.go @@ -1,3 +1,7 @@ package main -func potatoes() {} +import "strings" + +func potatoes(word string) int { + return strings.Count(word, "potato") +} diff --git a/exercise1/problem6/main.go b/exercise1/problem6/main.go index 06043890..eb87a9c5 100644 --- a/exercise1/problem6/main.go +++ b/exercise1/problem6/main.go @@ -1,3 +1,19 @@ package main -func emojify() {} +import "strings" + +func emojify(word string) string { + if strings.Contains(word, "smile") { + word = strings.ReplaceAll(word, "smile", "🙂") + } + if strings.Contains(word, "grin") { + word = strings.ReplaceAll(word, "grin", "😀") + } + if strings.Contains(word, "sad") { + word = strings.ReplaceAll(word, "sad", "😥") + } + if strings.Contains(word, "mad") { + word = strings.ReplaceAll(word, "mad", "😠") + } + return word +} diff --git a/exercise1/problem7/main.go b/exercise1/problem7/main.go index 57c99b5c..addb6313 100644 --- a/exercise1/problem7/main.go +++ b/exercise1/problem7/main.go @@ -1,3 +1,11 @@ package main -func highestDigit() {} +func highestDigit(n int) (maxDigit int) { + for n > 0 { + if n%10 > maxDigit { + maxDigit = n % 10 + } + n /= 10 + } + return +} diff --git a/exercise1/problem8/main.go b/exercise1/problem8/main.go index 97fa0dae..ac7d7229 100644 --- a/exercise1/problem8/main.go +++ b/exercise1/problem8/main.go @@ -1,3 +1,11 @@ package main -func countVowels() {} +func countVowels(word string) (count int) { + for _, r := range word { + switch r { + case 'a', 'e', 'i', 'o', 'u': + count++ + } + } + return +} diff --git a/exercise1/problem9/main.go b/exercise1/problem9/main.go index e8c84a54..7aa6e484 100644 --- a/exercise1/problem9/main.go +++ b/exercise1/problem9/main.go @@ -1,7 +1,13 @@ package main -func bitwiseAND() {} +func bitwiseAND(n, m int) int { + return n & m +} -func bitwiseOR() {} +func bitwiseOR(n, m int) int { + return n | m +} -func bitwiseXOR() {} +func bitwiseXOR(n, m int) int { + return n ^ m +} From 1b42660b1136dfd25961f74c4d67b96e4addbabb Mon Sep 17 00:00:00 2001 From: aqzholsky <98736657+aqzholsky@users.noreply.github.com> Date: Fri, 27 Sep 2024 02:49:23 +0500 Subject: [PATCH 03/17] completed ex2 --- exercise2/problem1/problem1.go | 10 +++++++++- exercise2/problem10/problem10.go | 10 +++++++++- exercise2/problem11/problem11.go | 12 +++++++++++- exercise2/problem12/problem12.go | 10 +++++++++- exercise2/problem2/problem2.go | 12 +++++++++++- exercise2/problem3/problem3.go | 20 +++++++++++++++++++- exercise2/problem4/problem4.go | 9 ++++++++- exercise2/problem5/problem5.go | 16 +++++++++++++++- exercise2/problem6/problem6.go | 10 +++++++++- exercise2/problem7/problem7.go | 3 ++- exercise2/problem8/problem8.go | 13 +++++-------- exercise2/problem9/problem9.go | 12 +++++++++++- 12 files changed, 118 insertions(+), 19 deletions(-) diff --git a/exercise2/problem1/problem1.go b/exercise2/problem1/problem1.go index 4763006c..a7a885f6 100644 --- a/exercise2/problem1/problem1.go +++ b/exercise2/problem1/problem1.go @@ -1,4 +1,12 @@ package problem1 -func isChangeEnough() { +func isChangeEnough(changes [4]int, total float32) bool { + coinValues := [4]float32{0.25, 0.10, 0.05, 0.01} + var dollars float32 + + for i, coin := range changes { + dollars += float32(coin) * coinValues[i] + } + + return dollars >= total } diff --git a/exercise2/problem10/problem10.go b/exercise2/problem10/problem10.go index 7142a022..cde772a1 100644 --- a/exercise2/problem10/problem10.go +++ b/exercise2/problem10/problem10.go @@ -1,3 +1,11 @@ package problem10 -func factory() {} +func factory() (map[string]int, func(string) func(int)) { + brandInfo := make(map[string]int) + return brandInfo, func(brandName string) func(int) { + brandInfo[brandName] = 0 + return func(incrementValue int) { + brandInfo[brandName] += incrementValue + } + } +} diff --git a/exercise2/problem11/problem11.go b/exercise2/problem11/problem11.go index 33988711..9cbee8cd 100644 --- a/exercise2/problem11/problem11.go +++ b/exercise2/problem11/problem11.go @@ -1,3 +1,13 @@ package problem11 -func removeDups() {} +func removeDups[T comparable](slice []T) []T { + result := []T{} + seen := make(map[T]struct{}) + for _, value := range slice { + if _, ok := seen[value]; !ok { + seen[value] = struct{}{} + result = append(result, value) + } + } + return result +} diff --git a/exercise2/problem12/problem12.go b/exercise2/problem12/problem12.go index 4c1ae327..b2933886 100644 --- a/exercise2/problem12/problem12.go +++ b/exercise2/problem12/problem12.go @@ -1,3 +1,11 @@ package problem11 -func keysAndValues() {} +func keysAndValues[K comparable, V comparable](inp map[K]V) ([]K, []V) { + keys := []K{} + values := []V{} + for key, value := range inp { + keys = append(keys, key) + values = append(values, value) + } + return keys, values +} diff --git a/exercise2/problem2/problem2.go b/exercise2/problem2/problem2.go index fdb199f0..c2a429a0 100644 --- a/exercise2/problem2/problem2.go +++ b/exercise2/problem2/problem2.go @@ -1,4 +1,14 @@ package problem2 -func capitalize() { +import ( + "strings" +) + +func capitalize(names []string) []string { + for i, name := range names { + if len(name) > 0 { + names[i] = strings.ToUpper(string(name[0])) + strings.ToLower(name[1:]) + } + } + return names } diff --git a/exercise2/problem3/problem3.go b/exercise2/problem3/problem3.go index f183fafb..3d41a5fd 100644 --- a/exercise2/problem3/problem3.go +++ b/exercise2/problem3/problem3.go @@ -9,5 +9,23 @@ const ( lr dir = "lr" ) -func diagonalize() { +func diagonalize(n int, d dir) [][]int { + exp := make([][]int, n) + + for i := 0; i < n; i++ { + exp[i] = make([]int, n) + for j := 0; j < n; j++ { + switch d { + case "ul": + exp[i][j] = i + j + case "ll": + exp[i][j] = n - i + j - 1 + case "ur": + exp[i][j] = n + i - j - 1 + case "lr": + exp[i][j] = (n - i - 1) + (n - j - 1) + } + } + } + return exp } diff --git a/exercise2/problem4/problem4.go b/exercise2/problem4/problem4.go index 1f680a4d..d79ffdcc 100644 --- a/exercise2/problem4/problem4.go +++ b/exercise2/problem4/problem4.go @@ -1,4 +1,11 @@ package problem4 -func mapping() { +import "strings" + +func mapping(inp []string) map[string]string { + exp := make(map[string]string) + for _, value := range inp { + exp[value] = strings.ToUpper(value) + } + return exp } diff --git a/exercise2/problem5/problem5.go b/exercise2/problem5/problem5.go index 43fb96a4..3620d1fc 100644 --- a/exercise2/problem5/problem5.go +++ b/exercise2/problem5/problem5.go @@ -1,4 +1,18 @@ package problem5 -func products() { +import "sort" + +func products(catalog map[string]int, minPrice int) (exp []string) { + for product, price := range catalog { + if price >= minPrice { + exp = append(exp, product) + } + } + sort.Slice(exp, func(i, j int) bool { + if catalog[exp[i]] == catalog[exp[j]] { + return exp[i] < exp[j] + } + return catalog[exp[i]] > catalog[exp[j]] + }) + return } diff --git a/exercise2/problem6/problem6.go b/exercise2/problem6/problem6.go index 89fc5bfe..4fcf4194 100644 --- a/exercise2/problem6/problem6.go +++ b/exercise2/problem6/problem6.go @@ -1,4 +1,12 @@ package problem6 -func sumOfTwo() { +func sumOfTwo(a, b []int, sum int) bool { + for _, i := range a { + for _, j := range b { + if i+j == sum { + return true + } + } + } + return false } diff --git a/exercise2/problem7/problem7.go b/exercise2/problem7/problem7.go index 32514209..79f51068 100644 --- a/exercise2/problem7/problem7.go +++ b/exercise2/problem7/problem7.go @@ -1,4 +1,5 @@ package problem7 -func swap() { +func swap(a, b *int) { + *a, *b = *b, *a } diff --git a/exercise2/problem8/problem8.go b/exercise2/problem8/problem8.go index 9389d3b0..b28a0682 100644 --- a/exercise2/problem8/problem8.go +++ b/exercise2/problem8/problem8.go @@ -1,16 +1,13 @@ package problem8 func simplify(list []string) map[string]int { - var indMap map[string]int - - indMap = make(map[string]int) - load(&indMap, &list) - + indMap := make(map[string]int) + load(indMap, list) return indMap } -func load(m *map[string]int, students *[]string) { - for i, name := range *students { - (*m)[name] = i +func load(m map[string]int, students []string) { + for i, name := range students { + m[name] = i } } diff --git a/exercise2/problem9/problem9.go b/exercise2/problem9/problem9.go index fc96d21a..6d787ac4 100644 --- a/exercise2/problem9/problem9.go +++ b/exercise2/problem9/problem9.go @@ -1,3 +1,13 @@ package problem9 -func factory() {} +type resultType func(...int) []int + +func factory(multiple int) resultType { + return func(list ...int) []int { + result := make([]int, len(list)) + for i, value := range list { + result[i] = value * multiple + } + return result + } +} From 34b616a580f51d9624992f1895dd9d857e1c9867 Mon Sep 17 00:00:00 2001 From: aqzholsky <98736657+aqzholsky@users.noreply.github.com> Date: Fri, 27 Sep 2024 03:00:03 +0500 Subject: [PATCH 04/17] refactored --- exercise2/problem11/problem11.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/exercise2/problem11/problem11.go b/exercise2/problem11/problem11.go index 9cbee8cd..66aa7860 100644 --- a/exercise2/problem11/problem11.go +++ b/exercise2/problem11/problem11.go @@ -2,7 +2,7 @@ package problem11 func removeDups[T comparable](slice []T) []T { result := []T{} - seen := make(map[T]struct{}) + seen := map[T]struct{}{} for _, value := range slice { if _, ok := seen[value]; !ok { seen[value] = struct{}{} From 52367f9c6ab6f90966df13484bee16c7c904aa1b Mon Sep 17 00:00:00 2001 From: aqzholsky <98736657+aqzholsky@users.noreply.github.com> Date: Wed, 2 Oct 2024 21:24:23 +0500 Subject: [PATCH 05/17] WIP --- exercise3/problem1/problem1.go | 34 ++++++++++++++++++++++++++++++++- exercise3/problem2/problem2.go | 35 +++++++++++++++++++++++++++++++++- exercise3/problem3/problem3.go | 5 +++++ 3 files changed, 72 insertions(+), 2 deletions(-) diff --git a/exercise3/problem1/problem1.go b/exercise3/problem1/problem1.go index d45605c6..1011ad35 100644 --- a/exercise3/problem1/problem1.go +++ b/exercise3/problem1/problem1.go @@ -1,3 +1,35 @@ package problem1 -type Queue struct{} +import "errors" + +type Queue struct { + items []interface{} +} + +func (q *Queue) Enqueue(item interface{}) { + q.items = append(q.items, item) +} + +func (q *Queue) Dequeue() (interface{}, error) { + if q.IsEmpty() { + return nil, errors.New("Queue is empty") + } + item := q.items[0] + q.items = q.items[1:] + return item, nil +} + +func (q *Queue) Peek() (interface{}, error) { + if q.IsEmpty() { + return nil, errors.New("Queue is empty") + } + return q.items[0], nil +} + +func (q *Queue) Size() int { + return len(q.items) +} + +func (q *Queue) IsEmpty() bool { + return len(q.items) == 0 +} diff --git a/exercise3/problem2/problem2.go b/exercise3/problem2/problem2.go index e9059889..4cb503c6 100644 --- a/exercise3/problem2/problem2.go +++ b/exercise3/problem2/problem2.go @@ -1,3 +1,36 @@ package problem2 -type Stack struct{} +import "errors" + +type Stack struct { + items []interface{} +} + +func (s *Stack) Push(item interface{}) { + s.items = append(s.items, item) +} + +func (s *Stack) Pop() (interface{}, error) { + if s.IsEmpty() { + return nil, errors.New("Stack is empty") + } + lastIndex := s.Size() - 1 + item := s.items[lastIndex] + s.items = s.items[:lastIndex] + return item, nil +} + +func (s *Stack) Peek() (interface{}, error) { + if s.IsEmpty() { + return nil, errors.New("Stack is empty") + } + return s.items[s.Size()-1], nil +} + +func (s *Stack) Size() int { + return len(s.items) +} + +func (s *Stack) IsEmpty() bool { + return s.Size() == 0 +} diff --git a/exercise3/problem3/problem3.go b/exercise3/problem3/problem3.go index d8d79ac0..97fb4028 100644 --- a/exercise3/problem3/problem3.go +++ b/exercise3/problem3/problem3.go @@ -1,3 +1,8 @@ package problem3 type Set struct{} + +func NewSet() *Set { + + return &Set{} +} From 11b274223f180fabb34209d81d596ef1a860ead5 Mon Sep 17 00:00:00 2001 From: aqzholsky <98736657+aqzholsky@users.noreply.github.com> Date: Sat, 5 Oct 2024 17:35:48 +0500 Subject: [PATCH 06/17] ready for review --- .vscode/launch.json | 15 ++++ .vscode/settings.json | 22 ++++++ exercise3/problem3/problem3.go | 102 ++++++++++++++++++++++++- exercise3/problem4/problem4.go | 131 ++++++++++++++++++++++++++++++++- exercise3/problem5/problem5.go | 19 ++++- exercise3/problem6/problem6.go | 30 +++++++- exercise3/problem7/problem7.go | 44 +++++++++++ 7 files changed, 356 insertions(+), 7 deletions(-) create mode 100644 .vscode/launch.json create mode 100644 .vscode/settings.json diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 00000000..608d3c69 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,15 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Launch Package", + "type": "go", + "request": "launch", + "mode": "auto", + "program": "${fileDirname}" + } + ] +} \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 00000000..4fe3b603 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,22 @@ +{ + "workbench.colorCustomizations": { + "activityBar.activeBackground": "#fa1b49", + "activityBar.background": "#fa1b49", + "activityBar.foreground": "#e7e7e7", + "activityBar.inactiveForeground": "#e7e7e799", + "activityBarBadge.background": "#155e02", + "activityBarBadge.foreground": "#e7e7e7", + "commandCenter.border": "#e7e7e799", + "sash.hoverBorder": "#fa1b49", + "statusBar.background": "#dd0531", + "statusBar.foreground": "#e7e7e7", + "statusBarItem.hoverBackground": "#fa1b49", + "statusBarItem.remoteBackground": "#dd0531", + "statusBarItem.remoteForeground": "#e7e7e7", + "titleBar.activeBackground": "#dd0531", + "titleBar.activeForeground": "#e7e7e7", + "titleBar.inactiveBackground": "#dd053199", + "titleBar.inactiveForeground": "#e7e7e799" + }, + "peacock.color": "#dd0531" +} \ No newline at end of file diff --git a/exercise3/problem3/problem3.go b/exercise3/problem3/problem3.go index 97fb4028..a292d7df 100644 --- a/exercise3/problem3/problem3.go +++ b/exercise3/problem3/problem3.go @@ -1,8 +1,106 @@ package problem3 -type Set struct{} +type Set struct { + items map[interface{}]struct{} +} func NewSet() *Set { + return &Set{ + items: make(map[interface{}]struct{}), + } +} + +func (s *Set) Add(item interface{}) { + s.items[item] = struct{}{} +} + +func (s *Set) Remove(item interface{}) { + delete(s.items, item) +} + +func (s *Set) IsEmpty() bool { + return len(s.items) == 0 +} + +func (s *Set) Size() int { + return len(s.items) +} + +func (s *Set) Has(item interface{}) bool { + _, exists := s.items[item] + return exists +} + +func (s *Set) Copy() *Set { + resultSet := NewSet() + for key := range s.items { + resultSet.Add(key) + } + return resultSet +} + +func (s *Set) Difference(r *Set) *Set { + resultSet := NewSet() + for key := range s.items { + if !r.Has(key) { + resultSet.Add(key) + } + } + return resultSet +} + +func (s *Set) IsSubset(r *Set) bool { + for key := range s.items { + if !r.Has(key) { + return false + } + } + return true +} + +func (s *Set) List() []interface{} { + result := []interface{}{} + for key := range s.items { + result = append(result, key) + } + return result +} + +func Union(sets ...*Set) *Set { + resultSet := NewSet() + for _, set := range sets { + for key := range set.items { + resultSet.Add(key) + } + } + return resultSet +} + +func Intersect(sets ...*Set) *Set { + if len(sets) == 0 { + return NewSet() + } + + minSet := sets[0] + for _, set := range sets[1:] { + if set.Size() < minSet.Size() { + minSet = set + } + } + + resultSet := NewSet() + for key := range minSet.items { + isCommon := true + for _, set := range sets { + if !set.Has(key) { + isCommon = false + break + } + } + if isCommon { + resultSet.Add(key) + } + } - return &Set{} + return resultSet } diff --git a/exercise3/problem4/problem4.go b/exercise3/problem4/problem4.go index ebf78147..7ca4847f 100644 --- a/exercise3/problem4/problem4.go +++ b/exercise3/problem4/problem4.go @@ -1,3 +1,132 @@ package problem4 -type LinkedList struct{} +import ( + "errors" +) + +type Element[T comparable] struct { + value T + next *Element[T] +} + +type LinkedList[T comparable] struct { + head *Element[T] + tail *Element[T] + size int +} + +func (l *LinkedList[T]) Add(e *Element[T]) { + if l.head == nil { + l.head = e + l.tail = e + } else { + l.tail.next = e + l.tail = e + } + l.size++ +} + +func (l *LinkedList[T]) Size() int { + return l.size +} + +func (l *LinkedList[T]) Insert(e *Element[T], index int) error { + if index < 0 || index > l.size { + return errors.New("index out of range") + } + + if index == 0 { + e.next = l.head + l.head = e + if l.size == 0 { + l.tail = e + } + } else { + prev, err := l.findPreviousByIndex(index - 1) + if err != nil { + return err + } + e.next = prev.next + prev.next = e + if e.next == nil { + l.tail = e + } + } + l.size++ + return nil +} + +func (l *LinkedList[T]) Delete(e *Element[T]) error { + if l.IsEmpty() { + return errors.New("linkedlist is empty") + } + + if l.head.value == e.value { + l.head = l.head.next + if l.head == nil { + l.tail = nil + } + } else { + prev, err := l.findPrevious(e.value) + if err != nil { + return err + } + prev.next = prev.next.next + if prev.next == nil { + l.tail = prev + } + } + l.size-- + return nil +} + +func (l *LinkedList[T]) Find(value T) (*Element[T], error) { + current := l.head + for current != nil { + if current.value == value { + return current, nil + } + current = current.next + } + return nil, errors.New("value not found") +} + +func (l *LinkedList[T]) List() []T { + result := make([]T, 0, l.size) + for current := l.head; current != nil; current = current.next { + result = append(result, current.value) + } + return result +} + +func (l *LinkedList[T]) IsEmpty() bool { + return l.size == 0 +} + +func (l *LinkedList[T]) findPreviousByIndex(index int) (*Element[T], error) { + if index < 0 || index >= l.size { + return nil, errors.New("index out of range") + } + + current := l.head + for i := 0; i < index; i++ { + current = current.next + } + return current, nil +} + +func (l *LinkedList[T]) findPrevious(value T) (*Element[T], error) { + if l.head == nil || l.head.value == value { + return nil, errors.New("value not found") + } + + current := l.head + for current.next != nil && current.next.value != value { + current = current.next + } + + if current.next == nil { + return nil, errors.New("value not found") + } + return current, nil +} diff --git a/exercise3/problem5/problem5.go b/exercise3/problem5/problem5.go index 4177599f..c490a487 100644 --- a/exercise3/problem5/problem5.go +++ b/exercise3/problem5/problem5.go @@ -1,3 +1,20 @@ package problem5 -type Person struct{} +import "fmt" + +type Person struct { + name string + age int +} + +func (me *Person) compareAge(other *Person) string { + if other.age > me.age { + return fmt.Sprintf("%s is older than me.", other.name) + } + + if other.age < me.age { + return fmt.Sprintf("%s is younger than me.", other.name) + } + + return fmt.Sprintf("%s is the same age as me.", other.name) +} diff --git a/exercise3/problem6/problem6.go b/exercise3/problem6/problem6.go index 4e8d1af8..9a0fa6e5 100644 --- a/exercise3/problem6/problem6.go +++ b/exercise3/problem6/problem6.go @@ -1,7 +1,31 @@ package problem6 -type Animal struct{} +type Animal struct { + name string + legsNum int +} -type Insect struct{} +func (a *Animal) GetLegs() int { + return a.legsNum +} -func sumOfAllLegsNum() {} +type Insect struct { + name string + legsNum int +} + +func (i *Insect) GetLegs() int { + return i.legsNum +} + +type HasLegs interface { + GetLegs() int +} + +func sumOfAllLegsNum(list ...HasLegs) int { + total := 0 + for _, l := range list { + total += l.GetLegs() + } + return total +} diff --git a/exercise3/problem7/problem7.go b/exercise3/problem7/problem7.go index 26887151..d1773d93 100644 --- a/exercise3/problem7/problem7.go +++ b/exercise3/problem7/problem7.go @@ -1,10 +1,54 @@ package problem7 +import "fmt" + +type Treasury interface { + withdraw(int) +} + +type Post interface { + sendTo(string) +} + type BankAccount struct { + name string + balance int +} + +func (b *BankAccount) withdraw(amount int) { + b.balance -= amount } type FedexAccount struct { + name string + packages []string +} + +func (f *FedexAccount) sendTo(name string) { + f.packages = append(f.packages, fmt.Sprintf("%s send package to %s", f.name, name)) } type KazPostAccount struct { + name string + balance int + packages []string +} + +func (k *KazPostAccount) withdraw(amount int) { + k.balance -= amount +} + +func (k *KazPostAccount) sendTo(name string) { + k.packages = append(k.packages, fmt.Sprintf("%s send package to %s", k.name, name)) +} + +func withdrawMoney(amount int, accounts ...Treasury) { + for _, account := range accounts { + account.withdraw(amount) + } +} +func sendPackagesTo(name string, posts ...Post) { + for _, post := range posts { + post.sendTo(name) + } } From 2f925812201c4ce856584e484af60972e10c91dc Mon Sep 17 00:00:00 2001 From: aqzholsky <98736657+aqzholsky@users.noreply.github.com> Date: Sat, 5 Oct 2024 18:34:28 +0500 Subject: [PATCH 07/17] new function added --- .gitignore | 5 ++++ exercise3/problem4/problem4.go | 15 ++++++++++ exercise3/problem4/problem4_test.go | 45 +++++++++++++++++++++++++++++ 3 files changed, 65 insertions(+) diff --git a/.gitignore b/.gitignore index 09944b57..6061dea7 100644 --- a/.gitignore +++ b/.gitignore @@ -25,3 +25,8 @@ go.work # Students students.txt + +# VS Code +.vscode/ +*.code-workspace +.history/ diff --git a/exercise3/problem4/problem4.go b/exercise3/problem4/problem4.go index 7ca4847f..d3ae48dd 100644 --- a/exercise3/problem4/problem4.go +++ b/exercise3/problem4/problem4.go @@ -130,3 +130,18 @@ func (l *LinkedList[T]) findPrevious(value T) (*Element[T], error) { } return current, nil } + +func (l *LinkedList[T]) Reverse() { + var prev, next *Element[T] + current := l.head + l.tail = current + + for current != nil { + next = current.next + current.next = prev + prev = current + current = next + } + + l.head = prev +} diff --git a/exercise3/problem4/problem4_test.go b/exercise3/problem4/problem4_test.go index a8c68499..baee2e43 100644 --- a/exercise3/problem4/problem4_test.go +++ b/exercise3/problem4/problem4_test.go @@ -451,4 +451,49 @@ func TestLinkedList(t *testing.T) { } }) }) + + t.Run("Reverse", func(t *testing.T) { + table := []struct { + list []any + expected []any + }{ + { + []any{1, 2, 3, 4, 5}, + []any{5, 4, 3, 2, 1}, + }, + { + []any{"a", "b", "c", "d", "e"}, + []any{"e", "d", "c", "b", "a"}, + }, + { + []any{true, false}, + []any{false, true}, + }, + } + + for _, r := range table { + ll := &LinkedList[any]{} + for _, value := range r.list { + ll.Add( + &Element[any]{ + value: value, + }, + ) + } + + ll.Reverse() + + actual := ll.List() + if len(actual) != len(r.expected) { + t.Errorf("Reverse(%v) was incorrect, got size: %d, expected size: %d", r.list, len(actual), len(r.expected)) + } + + for i := 0; i < len(actual); i++ { + if actual[i] != r.expected[i] { + t.Errorf("Reverse(%v) was incorrect, actual value: %v, expect value: %v", r.list, actual[i], r.expected[i]) + } + } + } + + }) } From 383547f58b55bd8a61bf09fd1b706171efe18b16 Mon Sep 17 00:00:00 2001 From: Aqzhol Baqatay <98736657+aqzholsky@users.noreply.github.com> Date: Sat, 5 Oct 2024 18:35:37 +0500 Subject: [PATCH 08/17] Delete .vscode/settings.json --- .vscode/settings.json | 22 ---------------------- 1 file changed, 22 deletions(-) delete mode 100644 .vscode/settings.json diff --git a/.vscode/settings.json b/.vscode/settings.json deleted file mode 100644 index 4fe3b603..00000000 --- a/.vscode/settings.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "workbench.colorCustomizations": { - "activityBar.activeBackground": "#fa1b49", - "activityBar.background": "#fa1b49", - "activityBar.foreground": "#e7e7e7", - "activityBar.inactiveForeground": "#e7e7e799", - "activityBarBadge.background": "#155e02", - "activityBarBadge.foreground": "#e7e7e7", - "commandCenter.border": "#e7e7e799", - "sash.hoverBorder": "#fa1b49", - "statusBar.background": "#dd0531", - "statusBar.foreground": "#e7e7e7", - "statusBarItem.hoverBackground": "#fa1b49", - "statusBarItem.remoteBackground": "#dd0531", - "statusBarItem.remoteForeground": "#e7e7e7", - "titleBar.activeBackground": "#dd0531", - "titleBar.activeForeground": "#e7e7e7", - "titleBar.inactiveBackground": "#dd053199", - "titleBar.inactiveForeground": "#e7e7e799" - }, - "peacock.color": "#dd0531" -} \ No newline at end of file From 94e0482c1dfdb1b676af84b2f4e9298b2d2ae355 Mon Sep 17 00:00:00 2001 From: Aqzhol Baqatay <98736657+aqzholsky@users.noreply.github.com> Date: Sat, 5 Oct 2024 18:35:51 +0500 Subject: [PATCH 09/17] Delete .vscode/launch.json --- .vscode/launch.json | 15 --------------- 1 file changed, 15 deletions(-) delete mode 100644 .vscode/launch.json diff --git a/.vscode/launch.json b/.vscode/launch.json deleted file mode 100644 index 608d3c69..00000000 --- a/.vscode/launch.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - // Use IntelliSense to learn about possible attributes. - // Hover to view descriptions of existing attributes. - // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 - "version": "0.2.0", - "configurations": [ - { - "name": "Launch Package", - "type": "go", - "request": "launch", - "mode": "auto", - "program": "${fileDirname}" - } - ] -} \ No newline at end of file From efa85a13328c7cc79f701d8563204e4a14eb4b9c Mon Sep 17 00:00:00 2001 From: aqzholsky <98736657+aqzholsky@users.noreply.github.com> Date: Sat, 5 Oct 2024 18:38:21 +0500 Subject: [PATCH 10/17] description changed --- exercise3/problem4/README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/exercise3/problem4/README.md b/exercise3/problem4/README.md index dd6ea6bc..35c0b15c 100644 --- a/exercise3/problem4/README.md +++ b/exercise3/problem4/README.md @@ -32,4 +32,8 @@ Get the size of the linked list. Check if the linked list is empty. +- _Reverse_ + +Reverse linked list by changing the links between elements + ! Please check the tests for signature and more examples. From 8506459bf6476cdaffea502bbc6153eaedca8a42 Mon Sep 17 00:00:00 2001 From: aqzholsky <98736657+aqzholsky@users.noreply.github.com> Date: Tue, 29 Oct 2024 17:31:17 +0500 Subject: [PATCH 11/17] exercise 5 completed --- exercise5/problem1/problem1.go | 7 ++++++ exercise5/problem2/problem2.go | 39 ++++++++++++++++++++++++++++++++++ exercise5/problem3/problem3.go | 6 +++--- exercise5/problem4/problem4.go | 1 + exercise5/problem5/problem5.go | 21 ++++++++++++++++-- exercise5/problem6/problem6.go | 31 ++++++++++++++++++++++++--- exercise5/problem7/problem7.go | 24 ++++++++++++++++++++- exercise5/problem8/problem8.go | 14 +++++++++++- 8 files changed, 133 insertions(+), 10 deletions(-) diff --git a/exercise5/problem1/problem1.go b/exercise5/problem1/problem1.go index 4f514fab..8e71df1a 100644 --- a/exercise5/problem1/problem1.go +++ b/exercise5/problem1/problem1.go @@ -1,9 +1,16 @@ package problem1 +import "sync" + func incrementConcurrently(num int) int { + wg := new(sync.WaitGroup) + wg.Add(1) + go func() { + defer wg.Done() num++ }() + wg.Wait() return num } diff --git a/exercise5/problem2/problem2.go b/exercise5/problem2/problem2.go index 16d38e1d..b568b2fc 100644 --- a/exercise5/problem2/problem2.go +++ b/exercise5/problem2/problem2.go @@ -1,5 +1,10 @@ package problem2 +import ( + "runtime" + "sync" +) + // add - sequential code to add numbers, don't update it, just to illustrate concept func add(numbers []int) int64 { var sum int64 @@ -10,7 +15,41 @@ func add(numbers []int) int64 { } func addConcurrently(numbers []int) int64 { + cpuCount := runtime.NumCPU() + runtime.GOMAXPROCS(cpuCount) + chunkSize := len(numbers) / cpuCount + resultCh := make(chan int, cpuCount) + wg := new(sync.WaitGroup) + var sum int64 + for i := 0; i < cpuCount; i++ { + start := i * chunkSize + end := start + chunkSize + if i == cpuCount-1 { + end = len(numbers) + } + wg.Add(1) + go processAddChunks(numbers[start:end], resultCh, wg) + } + + go func() { + wg.Wait() + close(resultCh) + }() + + for result := range resultCh { + sum += int64(result) + } + return sum } + +func processAddChunks(chunk []int, resultCh chan<- int, wg *sync.WaitGroup) { + defer wg.Done() + result := 0 + for _, num := range chunk { + result += num + } + resultCh <- result +} diff --git a/exercise5/problem3/problem3.go b/exercise5/problem3/problem3.go index e085a51a..a261335c 100644 --- a/exercise5/problem3/problem3.go +++ b/exercise5/problem3/problem3.go @@ -1,11 +1,11 @@ package problem3 func sum(a, b int) int { - var c int + ch := make(chan int) go func(a, b int) { - c = a + b + ch <- a + b }(a, b) - return c + return <-ch } diff --git a/exercise5/problem4/problem4.go b/exercise5/problem4/problem4.go index b5899ddf..f8457faa 100644 --- a/exercise5/problem4/problem4.go +++ b/exercise5/problem4/problem4.go @@ -1,6 +1,7 @@ package problem4 func iter(ch chan<- int, nums []int) { + defer close(ch) for _, n := range nums { ch <- n } diff --git a/exercise5/problem5/problem5.go b/exercise5/problem5/problem5.go index ac192c58..16c45d89 100644 --- a/exercise5/problem5/problem5.go +++ b/exercise5/problem5/problem5.go @@ -1,8 +1,25 @@ package problem5 -func producer() {} +import "fmt" -func consumer() {} +func producer(words []string, ch chan<- string) { + defer close(ch) + for _, word := range words { + ch <- word + } +} + +func consumer(ch <-chan string) string { + var result string + for word := range ch { + if result == "" { + result += word + } else { + result += fmt.Sprintf(" %s", word) + } + } + return result +} func send( words []string, diff --git a/exercise5/problem6/problem6.go b/exercise5/problem6/problem6.go index e1beea87..0b0d6691 100644 --- a/exercise5/problem6/problem6.go +++ b/exercise5/problem6/problem6.go @@ -2,8 +2,33 @@ package problem6 type pipe func(in <-chan int) <-chan int -var multiplyBy2 pipe = func() {} +var multiplyBy2 pipe = func(in <-chan int) <-chan int { + out := make(chan int) + go func() { + for v := range in { + out <- v * 2 + } + close(out) + }() + return out +} -var add5 pipe = func() {} +var add5 pipe = func(in <-chan int) <-chan int { + out := make(chan int) + go func() { + for v := range in { + out <- v + 5 + } + close(out) + }() + return out +} -func piper(in <-chan int, pipes []pipe) <-chan int {} +func piper(in <-chan int, pipes []pipe) <-chan int { + var out <-chan int + for _, pipe := range pipes { + out = pipe(in) + in = out + } + return out +} diff --git a/exercise5/problem7/problem7.go b/exercise5/problem7/problem7.go index c3c1d0c9..267c4842 100644 --- a/exercise5/problem7/problem7.go +++ b/exercise5/problem7/problem7.go @@ -1,3 +1,25 @@ package problem7 -func multiplex(ch1 <-chan string, ch2 <-chan string) []string {} +import "sync" + +func multiplex(channels ...<-chan string) []string { + result := []string{} + wg := new(sync.WaitGroup) + wg.Add(len(channels)) + mx := new(sync.Mutex) + + for _, ch := range channels { + go func(c <-chan string) { + defer wg.Done() + for v := range c { + mx.Lock() + result = append(result, v) + mx.Unlock() + } + }(ch) + } + + wg.Wait() + + return result +} diff --git a/exercise5/problem8/problem8.go b/exercise5/problem8/problem8.go index 3e951b3b..bb2643f0 100644 --- a/exercise5/problem8/problem8.go +++ b/exercise5/problem8/problem8.go @@ -4,4 +4,16 @@ import ( "time" ) -func withTimeout(ch <-chan string, ttl time.Duration) string {} +func withTimeout(ch <-chan string, ttl time.Duration) string { + for { + select { + case msg, ok := <-ch: + if !ok { + return "channel closed" + } + return msg + case <-time.After(ttl): + return "timeout" + } + } +} From 31d0ea3498f34f1fb487d91e5dcb6c1840776c19 Mon Sep 17 00:00:00 2001 From: aqzholsky <98736657+aqzholsky@users.noreply.github.com> Date: Wed, 20 Nov 2024 22:35:32 +0500 Subject: [PATCH 12/17] WIP --- exercise6/problem1/problem1.go | 19 ++++++++++++++++++- exercise6/problem2/problem2.go | 22 ++++++++++++++++++++-- exercise6/problem3/problem3.go | 14 ++++++++++++++ 3 files changed, 52 insertions(+), 3 deletions(-) diff --git a/exercise6/problem1/problem1.go b/exercise6/problem1/problem1.go index ee453b24..ac4d481d 100644 --- a/exercise6/problem1/problem1.go +++ b/exercise6/problem1/problem1.go @@ -1,9 +1,26 @@ package problem1 +import "sync" + type bankAccount struct { blnc int + mx *sync.Mutex } func newAccount(blnc int) *bankAccount { - return &bankAccount{blnc} + return &bankAccount{blnc, &sync.Mutex{}} +} + +func (b *bankAccount) withdraw(amount int) { + defer b.mx.Unlock() + b.mx.Lock() + if b.blnc >= amount { + b.blnc -= amount + } +} + +func (b *bankAccount) deposit(amount int) { + defer b.mx.Unlock() + b.mx.Lock() + b.blnc += amount } diff --git a/exercise6/problem2/problem2.go b/exercise6/problem2/problem2.go index 97e02368..037de66e 100644 --- a/exercise6/problem2/problem2.go +++ b/exercise6/problem2/problem2.go @@ -1,6 +1,7 @@ package problem2 import ( + "sync" "time" ) @@ -8,13 +9,30 @@ var readDelay = 10 * time.Millisecond type bankAccount struct { blnc int + mx *sync.RWMutex } func newAccount(blnc int) *bankAccount { - return &bankAccount{blnc} + return &bankAccount{blnc, &sync.RWMutex{}} } func (b *bankAccount) balance() int { time.Sleep(readDelay) - return 0 + defer b.mx.RUnlock() + b.mx.RLock() + return b.blnc +} + +func (b *bankAccount) withdraw(amount int) { + defer b.mx.Unlock() + b.mx.Lock() + if b.blnc >= amount { + b.blnc -= amount + } +} + +func (b *bankAccount) deposit(amount int) { + defer b.mx.Unlock() + b.mx.Lock() + b.blnc += amount } diff --git a/exercise6/problem3/problem3.go b/exercise6/problem3/problem3.go index b34b90bb..acb946e2 100644 --- a/exercise6/problem3/problem3.go +++ b/exercise6/problem3/problem3.go @@ -1,5 +1,7 @@ package problem3 +import "sync/atomic" + type counter struct { val int64 } @@ -9,3 +11,15 @@ func newCounter() *counter { val: 0, } } + +func (c *counter) inc() { + atomic.AddInt64(&c.val, 1) +} + +func (c *counter) dec() { + atomic.AddInt64(&c.val, -1) +} + +func (c *counter) value() int64 { + return atomic.LoadInt64(&c.val) +} From 6fa7b661f01b56b6dd51f14fbfa3b748e5eb9434 Mon Sep 17 00:00:00 2001 From: aqzholsky <98736657+aqzholsky@users.noreply.github.com> Date: Tue, 3 Dec 2024 21:38:18 +0500 Subject: [PATCH 13/17] exercise 6 completed --- exercise6/problem4/problem4.go | 23 ++++++++++++++++++----- exercise6/problem5/problem5.go | 21 ++++++++++++++++----- exercise6/problem6/problem6.go | 5 ++--- exercise6/problem7/problem7.go | 12 +++++++++++- exercise6/problem8/problem8.go | 24 +++++++++++++++++++++++- 5 files changed, 70 insertions(+), 15 deletions(-) diff --git a/exercise6/problem4/problem4.go b/exercise6/problem4/problem4.go index 793449c9..7f53e5ef 100644 --- a/exercise6/problem4/problem4.go +++ b/exercise6/problem4/problem4.go @@ -1,31 +1,44 @@ package problem4 import ( + "sync" "time" ) -func worker(id int, _ *[]string, ch chan<- int) { - // TODO wait for shopping list to be completed +func worker(id int, shoppingList *[]string, ch chan<- int, cond *sync.Cond) { + defer cond.L.Unlock() + cond.L.Lock() + + if len(*shoppingList) == 0 { + cond.Wait() + } + ch <- id } -func updateShopList(shoppingList *[]string) { +func updateShopList(shoppingList *[]string, cond *sync.Cond) { time.Sleep(10 * time.Millisecond) + defer cond.L.Unlock() + cond.L.Lock() + *shoppingList = append(*shoppingList, "apples") *shoppingList = append(*shoppingList, "milk") *shoppingList = append(*shoppingList, "bake soda") + + cond.Signal() } func notifyOnShopListUpdate(shoppingList *[]string, numWorkers int) <-chan int { notifier := make(chan int) + cond := &sync.Cond{L: &sync.Mutex{}} for i := range numWorkers { - go worker(i+1, shoppingList, notifier) + go worker(i+1, shoppingList, notifier, cond) time.Sleep(time.Millisecond) // order matters } - go updateShopList(shoppingList) + go updateShopList(shoppingList, cond) return notifier } diff --git a/exercise6/problem5/problem5.go b/exercise6/problem5/problem5.go index 8e4a1703..a54d8522 100644 --- a/exercise6/problem5/problem5.go +++ b/exercise6/problem5/problem5.go @@ -1,31 +1,42 @@ package problem5 import ( + "sync" "time" ) -func worker(id int, shoppingList *[]string, ch chan<- int) { - // TODO wait for shopping list to be completed +func worker(id int, shoppingList *[]string, ch chan<- int, cond *sync.Cond) { + defer cond.L.Unlock() + cond.L.Lock() + for len(*shoppingList) == 0 { + cond.Wait() + } ch <- id } -func updateShopList(shoppingList *[]string) { +func updateShopList(shoppingList *[]string, cond *sync.Cond) { time.Sleep(10 * time.Millisecond) + defer cond.L.Unlock() + cond.L.Lock() + *shoppingList = append(*shoppingList, "apples") *shoppingList = append(*shoppingList, "milk") *shoppingList = append(*shoppingList, "bake soda") + + cond.Broadcast() } func notifyOnShopListUpdate(shoppingList *[]string, numWorkers int) <-chan int { notifier := make(chan int) + cond := &sync.Cond{L: &sync.Mutex{}} for i := range numWorkers { - go worker(i+1, shoppingList, notifier) + go worker(i+1, shoppingList, notifier, cond) time.Sleep(time.Millisecond) // order matters } - go updateShopList(shoppingList) + go updateShopList(shoppingList, cond) return notifier } diff --git a/exercise6/problem6/problem6.go b/exercise6/problem6/problem6.go index 0c1122b9..fcbf38a7 100644 --- a/exercise6/problem6/problem6.go +++ b/exercise6/problem6/problem6.go @@ -6,14 +6,13 @@ import ( func runTasks(init func()) { var wg sync.WaitGroup + onceInit := sync.OnceFunc(init) for range 10 { wg.Add(1) go func() { defer wg.Done() - - //TODO: modify so that load function gets called only once. - init() + onceInit() }() } wg.Wait() diff --git a/exercise6/problem7/problem7.go b/exercise6/problem7/problem7.go index ef49497b..d54925e3 100644 --- a/exercise6/problem7/problem7.go +++ b/exercise6/problem7/problem7.go @@ -3,17 +3,27 @@ package problem7 import ( "fmt" "math/rand" + "sync" "time" ) func task() { start := time.Now() var t *time.Timer + mx := &sync.Mutex{} + t = time.AfterFunc( randomDuration(), func() { + defer mx.Unlock() + mx.Lock() fmt.Println(time.Now().Sub(start)) - t.Reset(randomDuration()) + + func() { + defer mx.Unlock() + mx.Lock() + t.Reset(randomDuration()) + }() }, ) time.Sleep(5 * time.Second) diff --git a/exercise6/problem8/problem8.go b/exercise6/problem8/problem8.go index 949eb2d2..db71fcf9 100644 --- a/exercise6/problem8/problem8.go +++ b/exercise6/problem8/problem8.go @@ -1,3 +1,25 @@ package problem8 -func multiplex(chs []<-chan string) []string {} +import "sync" + +func multiplex(chs []<-chan string) []string { + result := []string{} + wg := new(sync.WaitGroup) + wg.Add(len(chs)) + mx := new(sync.Mutex) + + for _, ch := range chs { + go func(c <-chan string) { + defer wg.Done() + for v := range c { + mx.Lock() + result = append(result, v) + mx.Unlock() + } + }(ch) + } + + wg.Wait() + + return result +} From 3792fb5172eb1cfd801e325234679580d57b5723 Mon Sep 17 00:00:00 2001 From: aqzholsky <98736657+aqzholsky@users.noreply.github.com> Date: Tue, 3 Dec 2024 21:43:47 +0500 Subject: [PATCH 14/17] exercise 6 problem 8 solution changed --- exercise6/problem8/problem8.go | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/exercise6/problem8/problem8.go b/exercise6/problem8/problem8.go index db71fcf9..6c6ef8b7 100644 --- a/exercise6/problem8/problem8.go +++ b/exercise6/problem8/problem8.go @@ -5,21 +5,26 @@ import "sync" func multiplex(chs []<-chan string) []string { result := []string{} wg := new(sync.WaitGroup) - wg.Add(len(chs)) - mx := new(sync.Mutex) + resultCh := make(chan string) for _, ch := range chs { + wg.Add(1) go func(c <-chan string) { defer wg.Done() for v := range c { - mx.Lock() - result = append(result, v) - mx.Unlock() + resultCh <- v } }(ch) } - wg.Wait() + go func() { + wg.Wait() + close(resultCh) + }() + + for v := range resultCh { + result = append(result, v) + } return result } From 9f9105bc0635910c5c19aaa8e48d88490b0bf7a7 Mon Sep 17 00:00:00 2001 From: Talgat Date: Tue, 26 Nov 2024 18:22:45 +0500 Subject: [PATCH 15/17] add lesson7 --- exercise7/blogging-platform/README.md | 3 + exercise7/blogging-platform/go.mod | 5 ++ exercise7/blogging-platform/go.sum | 2 + exercise7/blogging-platform/main.go | 49 ++++++++++++ .../pkg/httputils/request/body.go | 76 +++++++++++++++++++ .../pkg/httputils/response/body.go | 33 ++++++++ .../pkg/httputils/statusError/main.go | 18 +++++ 7 files changed, 186 insertions(+) create mode 100644 exercise7/blogging-platform/README.md create mode 100644 exercise7/blogging-platform/go.mod create mode 100644 exercise7/blogging-platform/go.sum create mode 100644 exercise7/blogging-platform/main.go create mode 100644 exercise7/blogging-platform/pkg/httputils/request/body.go create mode 100644 exercise7/blogging-platform/pkg/httputils/response/body.go create mode 100644 exercise7/blogging-platform/pkg/httputils/statusError/main.go diff --git a/exercise7/blogging-platform/README.md b/exercise7/blogging-platform/README.md new file mode 100644 index 00000000..e6ef7017 --- /dev/null +++ b/exercise7/blogging-platform/README.md @@ -0,0 +1,3 @@ +# Blogging Platform + +Please check https://roadmap.sh/projects/blogging-platform-api. diff --git a/exercise7/blogging-platform/go.mod b/exercise7/blogging-platform/go.mod new file mode 100644 index 00000000..ca16e703 --- /dev/null +++ b/exercise7/blogging-platform/go.mod @@ -0,0 +1,5 @@ +module github.com/talgat-ruby/exercises-go/exercise7/blogging-platform + +go 1.23.3 + +require github.com/lib/pq v1.10.9 diff --git a/exercise7/blogging-platform/go.sum b/exercise7/blogging-platform/go.sum new file mode 100644 index 00000000..aeddeae3 --- /dev/null +++ b/exercise7/blogging-platform/go.sum @@ -0,0 +1,2 @@ +github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw= +github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= diff --git a/exercise7/blogging-platform/main.go b/exercise7/blogging-platform/main.go new file mode 100644 index 00000000..1ffa1477 --- /dev/null +++ b/exercise7/blogging-platform/main.go @@ -0,0 +1,49 @@ +package main + +import ( + "context" + "log/slog" + "os" + "os/signal" + + "github.com/talgat-ruby/exercises-go/exercise7/blogging-platform/internal/api" + "github.com/talgat-ruby/exercises-go/exercise7/blogging-platform/internal/db" +) + +func main() { + ctx, cancel := context.WithCancel(context.Background()) + + // db + _, err := db.New() + if err != nil { + slog.ErrorContext( + ctx, + "initialize service error", + "service", "db", + "error", err, + ) + panic(err) + } + + // api + a := api.New() + if err := a.Start(ctx); err != nil { + slog.ErrorContext( + ctx, + "initialize service error", + "service", "api", + "error", err, + ) + panic(err) + } + + go func() { + shutdown := make(chan os.Signal, 1) // Create channel to signify s signal being sent + signal.Notify(shutdown, os.Interrupt) // When an interrupt is sent, notify the channel + + sig := <-shutdown + slog.WarnContext(ctx, "signal received - shutting down...", "signal", sig) + + cancel() + }() +} diff --git a/exercise7/blogging-platform/pkg/httputils/request/body.go b/exercise7/blogging-platform/pkg/httputils/request/body.go new file mode 100644 index 00000000..92d639f4 --- /dev/null +++ b/exercise7/blogging-platform/pkg/httputils/request/body.go @@ -0,0 +1,76 @@ +package request + +import ( + "encoding/json" + "errors" + "fmt" + "io" + "net/http" + "strings" + + "github.com/talgat-ruby/exercises-go/exercise7/blogging-platform/pkg/httputils/statusError" +) + +func JSON(w http.ResponseWriter, r *http.Request, dst interface{}) error { + ct := r.Header.Get("Content-Type") + if ct != "" { + mediaType := strings.ToLower(strings.TrimSpace(strings.Split(ct, ";")[0])) + if mediaType != "application/json" { + msg := "Content-Type header is not application/json" + return statusError.New(http.StatusUnsupportedMediaType, msg) + } + } + + r.Body = http.MaxBytesReader(w, r.Body, 1048576) + + dec := json.NewDecoder(r.Body) + dec.DisallowUnknownFields() + + err := dec.Decode(&dst) + if err != nil { + var syntaxError *json.SyntaxError + var unmarshalTypeError *json.UnmarshalTypeError + + switch { + case errors.As(err, &syntaxError): + msg := fmt.Sprintf("Request body contains badly-formed JSON (at position %d)", syntaxError.Offset) + return statusError.New(http.StatusBadRequest, msg) + + case errors.Is(err, io.ErrUnexpectedEOF): + msg := "Request body contains badly-formed JSON" + return statusError.New(http.StatusBadRequest, msg) + + case errors.As(err, &unmarshalTypeError): + msg := fmt.Sprintf( + "Request body contains an invalid value for the %q field (at position %d)", + unmarshalTypeError.Field, + unmarshalTypeError.Offset, + ) + return statusError.New(http.StatusBadRequest, msg) + + case strings.HasPrefix(err.Error(), "json: unknown field "): + fieldName := strings.TrimPrefix(err.Error(), "json: unknown field ") + msg := fmt.Sprintf("Request body contains unknown field %s", fieldName) + return statusError.New(http.StatusBadRequest, msg) + + case errors.Is(err, io.EOF): + msg := "Request body must not be empty" + return statusError.New(http.StatusBadRequest, msg) + + case err.Error() == "http: request body too large": + msg := "Request body must not be larger than 1MB" + return statusError.New(http.StatusRequestEntityTooLarge, msg) + + default: + return err + } + } + + err = dec.Decode(&struct{}{}) + if !errors.Is(err, io.EOF) { + msg := "Request body must only contain a single JSON object" + return statusError.New(http.StatusBadRequest, msg) + } + + return nil +} diff --git a/exercise7/blogging-platform/pkg/httputils/response/body.go b/exercise7/blogging-platform/pkg/httputils/response/body.go new file mode 100644 index 00000000..e1fd78a8 --- /dev/null +++ b/exercise7/blogging-platform/pkg/httputils/response/body.go @@ -0,0 +1,33 @@ +package response + +import ( + "encoding/json" + "fmt" + "net/http" +) + +type DataResponse struct { + Data interface{} `json:"data"` +} + +func JSON(w http.ResponseWriter, status int, data interface{}) error { + if data == nil { + w.WriteHeader(http.StatusNoContent) + return nil + } + + js, err := json.Marshal(data) + if err != nil { + http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError) + return fmt.Errorf("JSON marshal error: %w", err) + } + + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(status) + if _, err := w.Write(js); err != nil { + http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError) + return fmt.Errorf("writer error: %w", err) + } + + return nil +} diff --git a/exercise7/blogging-platform/pkg/httputils/statusError/main.go b/exercise7/blogging-platform/pkg/httputils/statusError/main.go new file mode 100644 index 00000000..6cf4e1b6 --- /dev/null +++ b/exercise7/blogging-platform/pkg/httputils/statusError/main.go @@ -0,0 +1,18 @@ +package statusError + +type StatusError struct { + status int + msg string +} + +func New(status int, msg string) error { + return &StatusError{status, msg} +} + +func (st *StatusError) Error() string { + return st.msg +} + +func (st *StatusError) Status() int { + return st.status +} From 48a4b158120966defe92a4a31ccf1351789f8793 Mon Sep 17 00:00:00 2001 From: Talgat Date: Thu, 23 Jan 2025 19:03:48 +0500 Subject: [PATCH 16/17] add exercise9 --- exercise9/README.md | 42 ++++++++++++++++++++++++++++++++++++++++++ exercise9/go.mod | 3 +++ 2 files changed, 45 insertions(+) create mode 100644 exercise9/README.md create mode 100644 exercise9/go.mod diff --git a/exercise9/README.md b/exercise9/README.md new file mode 100644 index 00000000..5d54880e --- /dev/null +++ b/exercise9/README.md @@ -0,0 +1,42 @@ +# Exercise 9 + +Project + +## Teams + +Team 1 + +1. Имангали Аскар (controller) +2. Зернов Владислав (controller) +3. Курмашев Сабит (api) +4. Кабулов Нуртас (api) +5. Омаров Темирлан (db) +6. Сагиндиков Меирбек (db) + +Team 2 + +1. Тұрарова Айзада (controller) +2. Толеу Аян (controller) +3. Мырзаханов Алинур (api) +4. Еркибаев Зураб (api) +5. Бақатай Ақжол (db) +6. Бимаканова Мадина (db) + +Team 3 + +1. Кабдылкак Арнур (controller) +2. Калкин Ернар (controller) +3. Манкенов Арай (api) +4. Усербай Асылбек (api) +5. Камбаров Руслан (db) +6. Қайратұлы Шыңғысхан (db) + +Team 4 + +1. Жақуда Жарқынай (controller) +2. Жантасов Адлет (controller) +3. Туралин Аргын (api) +4. Алтынбек Жандос (api) +5. Жакупов Жандаулет (db) +6. Мұхаметқали Арайлым (db) +7. Кемалатдин Ғалымжан (your choice) diff --git a/exercise9/go.mod b/exercise9/go.mod new file mode 100644 index 00000000..72f28b6f --- /dev/null +++ b/exercise9/go.mod @@ -0,0 +1,3 @@ +module github.com/talgat-ruby/exercises-go/exercise9 + +go 1.23.5 From 2ecb6e20a278605f638cfe49dd9ee66e08bddda9 Mon Sep 17 00:00:00 2001 From: Talgat Date: Mon, 27 Jan 2025 18:18:10 +0500 Subject: [PATCH 17/17] update exercise9 --- exercise9/README.md | 40 ++++++---------------------------------- 1 file changed, 6 insertions(+), 34 deletions(-) diff --git a/exercise9/README.md b/exercise9/README.md index 5d54880e..ef1d468e 100644 --- a/exercise9/README.md +++ b/exercise9/README.md @@ -6,37 +6,9 @@ Project Team 1 -1. Имангали Аскар (controller) -2. Зернов Владислав (controller) -3. Курмашев Сабит (api) -4. Кабулов Нуртас (api) -5. Омаров Темирлан (db) -6. Сагиндиков Меирбек (db) - -Team 2 - -1. Тұрарова Айзада (controller) -2. Толеу Аян (controller) -3. Мырзаханов Алинур (api) -4. Еркибаев Зураб (api) -5. Бақатай Ақжол (db) -6. Бимаканова Мадина (db) - -Team 3 - -1. Кабдылкак Арнур (controller) -2. Калкин Ернар (controller) -3. Манкенов Арай (api) -4. Усербай Асылбек (api) -5. Камбаров Руслан (db) -6. Қайратұлы Шыңғысхан (db) - -Team 4 - -1. Жақуда Жарқынай (controller) -2. Жантасов Адлет (controller) -3. Туралин Аргын (api) -4. Алтынбек Жандос (api) -5. Жакупов Жандаулет (db) -6. Мұхаметқали Арайлым (db) -7. Кемалатдин Ғалымжан (your choice) +1. Тұрарова Айзада (api) +2. Манкенов Арай (api) +3. Усербай Асылбек (controller) +4. Кемалатдин Ғалымжан (controller) +5. Имангали Аскар (db) +6. Кабдылкак Арнур (db)