Skip to content

Conversation

@0xSangeet
Copy link

Challenge 3 Solution

Submitted by: @0xSangeet
Challenge: Challenge 3

Description

This PR contains my solution for Challenge 3.

Changes

  • Added solution file to challenge-3/submissions/0xSangeet/solution-template.go

Testing

  • Solution passes all test cases
  • Code follows Go best practices

Thank you for reviewing my submission! 🚀

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jan 19, 2026

Walkthrough

A new Go solution file is added with Employee and Manager types. The Manager struct contains methods to add and remove employees, calculate average salary, and find employees by ID. A demonstration main function adds two employees, removes one, retrieves the average salary, and locates an employee by ID.

Changes

Cohort / File(s) Summary
Employee Manager Solution
challenge-3/submissions/0xSangeet/solution-template.go
New file introducing Employee struct (ID, Name, Age, Salary) and Manager struct with slice of Employees. Implements AddEmployee, RemoveEmployee, GetAverageSalary, and FindEmployeeByID methods. RemoveEmployee continues scanning after removal without breaking. FindEmployeeByID returns pointer to loop variable (unsafe). Main function demonstrates adding, removing, and querying employees.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~12 minutes

Possibly related PRs

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly identifies the PR as a solution submission for Challenge 3 by a specific user, which aligns with the primary change of adding a solution file.
Description check ✅ Passed The description is directly related to the changeset, explaining the challenge submission, the file added, and testing status of the solution.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Fix all issues with AI agents
In `@challenge-3/submissions/0xSangeet/solution-template.go`:
- Around line 41-48: In Manager.FindEmployeeByID the loop returns &value which
is the address of the loop variable (a copy) instead of the actual slice
element; change to index-based access so you return the address of the element
in m.Employees (e.g., iterate with for i := range m.Employees and return
&m.Employees[i] when m.Employees[i].ID == id) to ensure the pointer references
the real slice element.
- Around line 20-26: The RemoveEmployee method is mutating m.Employees inside a
range loop which causes skipped elements and potential index-out-of-range
panics; replace the range loop with an index-based for i := 0; i <
len(m.Employees); i++ loop, check m.Employees[i].ID == id, remove the element
with the same append-slicing expression (m.Employees = append(m.Employees[:i],
m.Employees[i+1:]...)) and then immediately break out of the loop to stop
iterating after the deletion.

Comment on lines +20 to +26
func (m *Manager) RemoveEmployee(id int) {
for index, value := range m.Employees {
if value.ID == id {
m.Employees = append(m.Employees[:index], m.Employees[index+1:]...)
}
}
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

# Search for the Employee struct definition to understand the context
cd challenge-3/submissions/0xSangeet && find . -name "*.go" -type f | head -20

Repository: RezaSi/go-interview-practice

Length of output: 94


🏁 Script executed:

# Also check the actual file in question
cat -n challenge-3/submissions/0xSangeet/solution-template.go | head -40

Repository: RezaSi/go-interview-practice

Length of output: 1011


🏁 Script executed:

# Search for Employee struct definition
rg "type Employee" challenge-3/submissions/0xSangeet/ -A 5

Repository: RezaSi/go-interview-practice

Length of output: 481


🌐 Web query:

Go range loop mutation slice append behavior during iteration

💡 Result:

Short answer

  • A for … range over a slice evaluates the range expression once and iterates a fixed number of times: 0..len(x)-1 (the len is taken at loop start). The loop index/value are produced from that snapshot. (go.dev)
  • The range value (the second/only variable) is a copy for value types — modifying that loop variable does not change the element in the slice. For pointers, a common pitfall is appending &v where v is the loop copy (you end up appending the same address repeatedly). Use &s[i] if you need the element’s address. (rednafi.com)
  • append may reallocate the underlying array (or reuse it if capacity allows). Appending inside the range will change the slice value (and may grow its backing array), but the range’s iteration count and the iteration values are unaffected by those runtime changes. If you need to iterate over newly appended elements, use an index-based for loop and adjust the upper bound dynamically. (go.dev)

Practical rules

  • Don’t rely on range seeing elements appended during iteration — it won’t.
  • If you must mutate elements in-place, iterate by index: for i := range s { s[i] = ... }.
  • If you must append and then visit appended elements, use a for i := 0; i < len(s); i++ { … } loop and read len(s) each iteration (or manage i and len explicitly). (go.dev)

References
[1] Go language spec — For range semantics. (go.dev)
[2] Go blog — Slices: usage and internals (append/backing array behavior). (go.dev)
[3] Practical notes / examples on range behavior and value copying. (rednafi.com)

Citations:


Mutating the slice during range iteration causes index out-of-range panic.

When you remove an element from m.Employees mid-iteration, the slice becomes shorter but the range loop continues with its fixed iteration count (determined at the start). Subsequent loop iterations then try to access indices that no longer exist in the shortened slice.

Additionally, this skips elements: when the element at index is removed, the element at index+1 shifts down to index, but the loop has already moved past that position.

Use an index-based for loop with break after the first match:

🛠️ Proposed fix
func (m *Manager) RemoveEmployee(id int) {
-	for index, value := range m.Employees {
-	    if value.ID == id {
-	        m.Employees = append(m.Employees[:index], m.Employees[index+1:]...)
-	    }
-	}
+	for i := 0; i < len(m.Employees); i++ {
+		if m.Employees[i].ID == id {
+			m.Employees = append(m.Employees[:i], m.Employees[i+1:]...)
+			break
+		}
+	}
}
🤖 Prompt for AI Agents
In `@challenge-3/submissions/0xSangeet/solution-template.go` around lines 20 - 26,
The RemoveEmployee method is mutating m.Employees inside a range loop which
causes skipped elements and potential index-out-of-range panics; replace the
range loop with an index-based for i := 0; i < len(m.Employees); i++ loop, check
m.Employees[i].ID == id, remove the element with the same append-slicing
expression (m.Employees = append(m.Employees[:i], m.Employees[i+1:]...)) and
then immediately break out of the loop to stop iterating after the deletion.

Comment on lines +41 to +48
func (m *Manager) FindEmployeeByID(id int) *Employee {
for _, value := range m.Employees {
if value.ID == id {
return &value
}
}
return nil
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🌐 Web query:

Go range loop variable pointer semantics slice element copy

💡 Result:

Short answer: when you do for _, v := range slice in Go, v is a single variable reused each iteration and receives a copy of the slice element. Taking &v therefore yields the same address every time (and points to the last value after the loop). The range expression itself is evaluated once and the spec describes how iteration values are produced. [1][2]

Consequences

  • Modifying v does not change slice[i] (v is a copy). [1][3]
  • Appending &v (or storing it) in the loop will store repeated pointers to the same reused variable. [3][4]

Fixes (choose one depending on intent)

  • Take address of the actual element: for i := range s { ptr = &s[i] } — pointers refer to the slice backing array element. [4][3]
  • Create a new per-iteration variable and take its address: for _, v := range s { v2 := v; ptr = &v2 } — each iteration gets a fresh variable. [3][4]
  • Use an index-based loop when you need to modify elements in place: for i := range s { s[i] = ... } . [7]

Authoritative references

  • Go spec: range evaluated once; array/slice semantics and iteration values. [1]
  • Go wiki / common mistakes: example and recommended fixes (copy var or use &s[i]). [3]
  • Discussions/examples of the pointer-gotcha and fixes. [4][5]

References
[1] Go language spec — Range clause and iteration values.
[2] “Does range copy the slice in Go?” (explanation of temporary copy/semantics).
[3] Go Wiki — Common Mistakes (loop-variable address example).
[4] Evan Jones — “Don't take the address of loop variables” / StackOverflow examples.


🏁 Script executed:

find . -name "solution-template.go" -path "*/0xSangeet/*" | head -5

Repository: RezaSi/go-interview-practice

Length of output: 128


🏁 Script executed:

cat -n ./challenge-3/submissions/0xSangeet/solution-template.go | sed -n '35,55p'

Repository: RezaSi/go-interview-practice

Length of output: 707


🏁 Script executed:

cat -n ./challenge-3/submissions/0xSangeet/solution-template.go | sed -n '1,40p'

Repository: RezaSi/go-interview-practice

Length of output: 1011


Return a pointer to the slice element, not the range variable.

value is a copy of each iteration; returning &value gives a pointer to the loop variable (which is reused and temporary), not to the actual element in m.Employees. Use index-based access to return the actual element's address.

✅ Proposed fix
func (m *Manager) FindEmployeeByID(id int) *Employee {
-	for _, value := range m.Employees {
-	    if value.ID == id {
-	        return &value
-	    }
-	}
+	for i := range m.Employees {
+		if m.Employees[i].ID == id {
+			return &m.Employees[i]
+		}
+	}
 	return nil
}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
func (m *Manager) FindEmployeeByID(id int) *Employee {
for _, value := range m.Employees {
if value.ID == id {
return &value
}
}
return nil
}
func (m *Manager) FindEmployeeByID(id int) *Employee {
for i := range m.Employees {
if m.Employees[i].ID == id {
return &m.Employees[i]
}
}
return nil
}
🤖 Prompt for AI Agents
In `@challenge-3/submissions/0xSangeet/solution-template.go` around lines 41 - 48,
In Manager.FindEmployeeByID the loop returns &value which is the address of the
loop variable (a copy) instead of the actual slice element; change to
index-based access so you return the address of the element in m.Employees
(e.g., iterate with for i := range m.Employees and return &m.Employees[i] when
m.Employees[i].ID == id) to ensure the pointer references the real slice
element.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant