Skip to content

Commit 232e628

Browse files
add: 42_wait_group exercise with template, solution, and tests (#162)
Co-authored-by: kaushalyap <24698778+kaushalyap@users.noreply.github.com>
1 parent 6e5a500 commit 232e628

4 files changed

Lines changed: 114 additions & 0 deletions

File tree

internal/exercises/catalog.yaml

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,17 @@ concepts:
197197
hints:
198198
- Use `select` to handle multiple channel operations concurrently.
199199
- Use `time.After` to simulate a 5 microsecond timeout.
200+
- slug: 42_wait_group
201+
title: WaitGroups
202+
test_regex: ".*"
203+
difficulty: beginner
204+
topics: ["concurrency", "sync", "goroutines"]
205+
hints:
206+
- "Use sync.WaitGroup to wait for all launched goroutines."
207+
- "Call wg.Add(1) before starting a goroutine and wg.Done() when it finishes."
208+
- "Close result channels after wg.Wait() so collectors can range over them."
209+
- "Capture loop variables correctly inside goroutines (e.g., `n := n`)."
210+
- "Return results as a slice — order does not need to match input order."
200211
projects:
201212
- slug: 101_text_analyzer
202213
title: Text Analyzer (Easy)
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
package waitgroup
2+
3+
import "sync"
4+
5+
func Squares(nums []int) []int {
6+
length := len(nums)
7+
if length == 0 {
8+
return []int{}
9+
}
10+
11+
ch := make(chan int, length)
12+
var wg sync.WaitGroup
13+
wg.Add(length)
14+
15+
for _, n := range nums {
16+
n := n
17+
go func() {
18+
defer wg.Done()
19+
ch <- n * n
20+
}()
21+
}
22+
23+
go func() {
24+
wg.Wait()
25+
close(ch)
26+
}()
27+
28+
out := make([]int, 0, length)
29+
for v := range ch {
30+
out = append(out, v)
31+
}
32+
return out
33+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
package waitgroup
2+
3+
import "sync"
4+
5+
// Squares takes a slice of numbers and should return a slice
6+
// containing the square of each number.
7+
8+
// Use goroutines to perform the calculations concurrently,
9+
// and use sync.WaitGroup to make sure all goroutines finish
10+
// before returning the results.
11+
12+
// Steps:
13+
// 1. Create a channel to collect results.
14+
// 2. Start one goroutine per number.
15+
// 3. Each goroutine should send n*n into the channel.
16+
// 4. Wait for all goroutines to finish, then close the channel.
17+
// 5. Collect all values from the channel into a slice and return it.
18+
19+
func Squares(nums []int) []int {
20+
var wg sync.WaitGroup
21+
22+
// TODO: implement the logic here
23+
24+
return nil
25+
}
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
package waitgroup
2+
3+
import (
4+
"reflect"
5+
"sort"
6+
"testing"
7+
"time"
8+
)
9+
10+
func equalIgnoreOrder(a, b []int) bool {
11+
if len(a) != len(b) {
12+
return false
13+
}
14+
x, y := append([]int(nil), a...), append([]int(nil), b...)
15+
sort.Ints(x)
16+
sort.Ints(y)
17+
return reflect.DeepEqual(x, y)
18+
}
19+
20+
func TestSquaresBasic(t *testing.T) {
21+
got := Squares([]int{1, 2, 3, 4})
22+
want := []int{1, 4, 9, 16}
23+
if !equalIgnoreOrder(got, want) {
24+
t.Fatalf("Squares() = %v; want %v", got, want)
25+
}
26+
}
27+
28+
func TestSquaresEmpty(t *testing.T) {
29+
if len(Squares([]int{})) != 0 {
30+
t.Fatal("expected empty result for empty input")
31+
}
32+
}
33+
34+
func TestSquaresTimeout(t *testing.T) {
35+
done := make(chan struct{})
36+
go func() {
37+
_ = Squares([]int{5, 6, 7})
38+
close(done)
39+
}()
40+
select {
41+
case <-done:
42+
case <-time.After(2 * time.Second):
43+
t.Fatal("function deadlocked")
44+
}
45+
}

0 commit comments

Comments
 (0)