go-01-unique
1.000
Challenge · difficulty 1/5
# Unique preserving order
Implement **`solution.go`** in `package challenge` exporting:
```go
func Unique(xs []int) []int
```
Return a new slice containing the elements of `xs` with duplicates removed, keeping each value at
the position of its **first occurrence**.
Rules:
- Preserve **first-occurrence order** — do not sort the result.
- Each distinct value appears exactly once.
- Do **not** mutate the input slice.
- For an empty (or nil) input, return an **empty, non-nil** slice (length 0).
Examples:
```go
Unique([]int{3, 1, 3, 2, 1}) // => [3, 1, 2]
Unique([]int{1, 2, 3}) // => [1, 2, 3]
Unique([]int{5, 5, 5}) // => [5]
Unique([]int{}) // => [] (non-nil, length 0)
```
tests/solution_test.go
package challenge
import (
"reflect"
"testing"
)
func TestUnique(t *testing.T) {
cases := []struct {
name string
in []int
want []int
}{
{"removes duplicates preserving order", []int{3, 1, 3, 2, 1}, []int{3, 1, 2}},
{"already unique unchanged", []int{1, 2, 3}, []int{1, 2, 3}},
{"all same collapses to one", []int{5, 5, 5}, []int{5}},
{"empty returns empty", []int{}, []int{}},
{"single element", []int{42}, []int{42}},
{"negatives and zero", []int{0, -1, 0, -1, 2}, []int{0, -1, 2}},
}
for _, tc := range cases {
t.Run(tc.name, func(t *testing.T) {
got := Unique(tc.in)
if !reflect.DeepEqual(got, tc.want) {
t.Errorf("Unique(%v) = %v, want %v", tc.in, got, tc.want)
}
})
}
}
func TestUniqueReturnsNonNil(t *testing.T) {
if Unique([]int{}) == nil {
t.Error("Unique should return a non-nil slice for empty input")
}
if Unique(nil) == nil {
t.Error("Unique should return a non-nil slice for nil input")
}
}
func TestUniqueDoesNotMutateInput(t *testing.T) {
in := []int{1, 1, 2}
_ = Unique(in)
if !reflect.DeepEqual(in, []int{1, 1, 2}) {
t.Errorf("input was mutated: got %v", in)
}
}
System prompt
You are an expert programmer. Solve the task exactly as specified. Output your solution as fenced code blocks using the required file name(s) and the exact function/type signatures requested. Prefer correctness; do not include prose outside code unless asked.
Proposed solution
```go
package challenge
func Unique(xs []int) []int {
seen := make(map[int]bool)
result := []int{}
for _, v := range xs {
if !seen[v] {
seen[v] = true
result = append(result, v)
}
}
return result
}
```Test output (stdout)
e":"2026-07-02T04:33:47.923454138+02:00","Action":"output","Package":"challenge","Test":"TestUnique/all_same_collapses_to_one","Output":"--- PASS: TestUnique/all_same_collapses_to_one (0.00s)\n"}
{"Time":"2026-07-02T04:33:47.923458098+02:00","Action":"pass","Package":"challenge","Test":"TestUnique/all_same_collapses_to_one","Elapsed":0}
{"Time":"2026-07-02T04:33:47.923459678+02:00","Action":"run","Package":"challenge","Test":"TestUnique/empty_returns_empty"}
{"Time":"2026-07-02T04:33:47.923460458+02:00","Action":"output","Package":"challenge","Test":"TestUnique/empty_returns_empty","Output":"=== RUN TestUnique/empty_returns_empty\n"}
{"Time":"2026-07-02T04:33:47.923462498+02:00","Action":"output","Package":"challenge","Test":"TestUnique/empty_returns_empty","Output":"--- PASS: TestUnique/empty_returns_empty (0.00s)\n"}
{"Time":"2026-07-02T04:33:47.923463668+02:00","Action":"pass","Package":"challenge","Test":"TestUnique/empty_returns_empty","Elapsed":0}
{"Time":"2026-07-02T04:33:47.923464698+02:00","Action":"run","Package":"challenge","Test":"TestUnique/single_element"}
{"Time":"2026-07-02T04:33:47.923465518+02:00","Action":"output","Package":"challenge","Test":"TestUnique/single_element","Output":"=== RUN TestUnique/single_element\n"}
{"Time":"2026-07-02T04:33:47.923466888+02:00","Action":"output","Package":"challenge","Test":"TestUnique/single_element","Output":"--- PASS: TestUnique/single_element (0.00s)\n"}
{"Time":"2026-07-02T04:33:47.923468058+02:00","Action":"pass","Package":"challenge","Test":"TestUnique/single_element","Elapsed":0}
{"Time":"2026-07-02T04:33:47.923468938+02:00","Action":"run","Package":"challenge","Test":"TestUnique/negatives_and_zero"}
{"Time":"2026-07-02T04:33:47.923469808+02:00","Action":"output","Package":"challenge","Test":"TestUnique/negatives_and_zero","Output":"=== RUN TestUnique/negatives_and_zero\n"}
{"Time":"2026-07-02T04:33:47.923471518+02:00","Action":"output","Package":"challenge","Test":"TestUnique/negatives_and_zero","Output":"--- PASS: TestUnique/negatives_and_zero (0.00s)\n"}
{"Time":"2026-07-02T04:33:47.923472548+02:00","Action":"pass","Package":"challenge","Test":"TestUnique/negatives_and_zero","Elapsed":0}
{"Time":"2026-07-02T04:33:47.923473668+02:00","Action":"output","Package":"challenge","Test":"TestUnique","Output":"--- PASS: TestUnique (0.00s)\n"}
{"Time":"2026-07-02T04:33:47.923474738+02:00","Action":"pass","Package":"challenge","Test":"TestUnique","Elapsed":0}
{"Time":"2026-07-02T04:33:47.923475888+02:00","Action":"run","Package":"challenge","Test":"TestUniqueReturnsNonNil"}
{"Time":"2026-07-02T04:33:47.923476838+02:00","Action":"output","Package":"challenge","Test":"TestUniqueReturnsNonNil","Output":"=== RUN TestUniqueReturnsNonNil\n"}
{"Time":"2026-07-02T04:33:47.923477968+02:00","Action":"output","Package":"challenge","Test":"TestUniqueReturnsNonNil","Output":"--- PASS: TestUniqueReturnsNonNil (0.00s)\n"}
{"Time":"2026-07-02T04:33:47.923479368+02:00","Action":"pass","Package":"challenge","Test":"TestUniqueReturnsNonNil","Elapsed":0}
{"Time":"2026-07-02T04:33:47.923480308+02:00","Action":"run","Package":"challenge","Test":"TestUniqueDoesNotMutateInput"}
{"Time":"2026-07-02T04:33:47.923481918+02:00","Action":"output","Package":"challenge","Test":"TestUniqueDoesNotMutateInput","Output":"=== RUN TestUniqueDoesNotMutateInput\n"}
{"Time":"2026-07-02T04:33:47.923483438+02:00","Action":"output","Package":"challenge","Test":"TestUniqueDoesNotMutateInput","Output":"--- PASS: TestUniqueDoesNotMutateInput (0.00s)\n"}
{"Time":"2026-07-02T04:33:47.923484358+02:00","Action":"pass","Package":"challenge","Test":"TestUniqueDoesNotMutateInput","Elapsed":0}
{"Time":"2026-07-02T04:33:47.923485348+02:00","Action":"output","Package":"challenge","Output":"PASS\n"}
{"Time":"2026-07-02T04:33:47.923538728+02:00","Action":"output","Package":"challenge","Output":"ok \tchallenge\t0.001s\n"}
{"Time":"2026-07-02T04:33:47.923556278+02:00","Action":"pass","Package":"challenge","Elapsed":0.001}
Reasoning (chain-of-thought)
The task is to implement a function `Unique` in Go that removes duplicates from a slice of integers while preserving the order of first occurrences.
Key requirements:
1. Return a new slice (don't mutate input)
2. Preserve first-occurrence order
3. Each distinct value appears exactly once
4. For empty/nil input, return empty non-nil slice (length 0)
The approach:
1. Create a result slice
2. Use a map to track which values we've already seen
3. Iterate through the input slice
4. For each element, if we haven't seen it before, add it to the result and mark it as seen
5. Return the result slice
Let me write the code:
```go
package challenge
func Unique(xs []int) []int {
seen := make(map[int]bool)
result := []int{}
for _, v := range xs {
if !seen[v] {
seen[v] = true
result = append(result, v)
}
}
return result
}
```
This should work correctly:
- For `[]int{3, 1, 3, 2, 1}`:
- 3: not seen, add to result, mark seen
- 1: not seen, add to result, mark seen
- 3: already seen, skip
- 2: not seen, add to result, mark seen
- 1: already seen, skip
- Result: [3, 1, 2] ✓
- For `[]int{}`: loop doesn't run, returns empty slice ✓
- For `nil`: same as empty slice ✓
The result slice is non-nil (it's initialized as `[]int{}`), and has length 0 for empty input.
Let me verify the edge cases:
- Empty slice: `[]int{}` - loop doesn't execute, returns `[]int{}` which is non-nil with length 0 ✓
- Nil slice: `nil` - loop doesn't execute, returns `[]int{}` which is non-nil with length 0 ✓
Both edge cases are handled correctly by the implementation.