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 _, x := range xs {
if !seen[x] {
seen[x] = true
result = append(result, x)
}
}
return result
}
```Test output (stdout)
e":"2026-07-01T22:47:43.548629657+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-01T22:47:43.548631247+02:00","Action":"pass","Package":"challenge","Test":"TestUnique/all_same_collapses_to_one","Elapsed":0}
{"Time":"2026-07-01T22:47:43.548632107+02:00","Action":"run","Package":"challenge","Test":"TestUnique/empty_returns_empty"}
{"Time":"2026-07-01T22:47:43.548634117+02:00","Action":"output","Package":"challenge","Test":"TestUnique/empty_returns_empty","Output":"=== RUN TestUnique/empty_returns_empty\n"}
{"Time":"2026-07-01T22:47:43.548635147+02:00","Action":"output","Package":"challenge","Test":"TestUnique/empty_returns_empty","Output":"--- PASS: TestUnique/empty_returns_empty (0.00s)\n"}
{"Time":"2026-07-01T22:47:43.548636057+02:00","Action":"pass","Package":"challenge","Test":"TestUnique/empty_returns_empty","Elapsed":0}
{"Time":"2026-07-01T22:47:43.548637177+02:00","Action":"run","Package":"challenge","Test":"TestUnique/single_element"}
{"Time":"2026-07-01T22:47:43.548638027+02:00","Action":"output","Package":"challenge","Test":"TestUnique/single_element","Output":"=== RUN TestUnique/single_element\n"}
{"Time":"2026-07-01T22:47:43.548640217+02:00","Action":"output","Package":"challenge","Test":"TestUnique/single_element","Output":"--- PASS: TestUnique/single_element (0.00s)\n"}
{"Time":"2026-07-01T22:47:43.548641147+02:00","Action":"pass","Package":"challenge","Test":"TestUnique/single_element","Elapsed":0}
{"Time":"2026-07-01T22:47:43.548642418+02:00","Action":"run","Package":"challenge","Test":"TestUnique/negatives_and_zero"}
{"Time":"2026-07-01T22:47:43.548643288+02:00","Action":"output","Package":"challenge","Test":"TestUnique/negatives_and_zero","Output":"=== RUN TestUnique/negatives_and_zero\n"}
{"Time":"2026-07-01T22:47:43.548644328+02:00","Action":"output","Package":"challenge","Test":"TestUnique/negatives_and_zero","Output":"--- PASS: TestUnique/negatives_and_zero (0.00s)\n"}
{"Time":"2026-07-01T22:47:43.548645338+02:00","Action":"pass","Package":"challenge","Test":"TestUnique/negatives_and_zero","Elapsed":0}
{"Time":"2026-07-01T22:47:43.548646458+02:00","Action":"output","Package":"challenge","Test":"TestUnique","Output":"--- PASS: TestUnique (0.00s)\n"}
{"Time":"2026-07-01T22:47:43.548647708+02:00","Action":"pass","Package":"challenge","Test":"TestUnique","Elapsed":0}
{"Time":"2026-07-01T22:47:43.548648668+02:00","Action":"run","Package":"challenge","Test":"TestUniqueReturnsNonNil"}
{"Time":"2026-07-01T22:47:43.548649478+02:00","Action":"output","Package":"challenge","Test":"TestUniqueReturnsNonNil","Output":"=== RUN TestUniqueReturnsNonNil\n"}
{"Time":"2026-07-01T22:47:43.548650828+02:00","Action":"output","Package":"challenge","Test":"TestUniqueReturnsNonNil","Output":"--- PASS: TestUniqueReturnsNonNil (0.00s)\n"}
{"Time":"2026-07-01T22:47:43.548651848+02:00","Action":"pass","Package":"challenge","Test":"TestUniqueReturnsNonNil","Elapsed":0}
{"Time":"2026-07-01T22:47:43.548652698+02:00","Action":"run","Package":"challenge","Test":"TestUniqueDoesNotMutateInput"}
{"Time":"2026-07-01T22:47:43.548653488+02:00","Action":"output","Package":"challenge","Test":"TestUniqueDoesNotMutateInput","Output":"=== RUN TestUniqueDoesNotMutateInput\n"}
{"Time":"2026-07-01T22:47:43.548655148+02:00","Action":"output","Package":"challenge","Test":"TestUniqueDoesNotMutateInput","Output":"--- PASS: TestUniqueDoesNotMutateInput (0.00s)\n"}
{"Time":"2026-07-01T22:47:43.548656018+02:00","Action":"pass","Package":"challenge","Test":"TestUniqueDoesNotMutateInput","Elapsed":0}
{"Time":"2026-07-01T22:47:43.548658718+02:00","Action":"output","Package":"challenge","Output":"PASS\n"}
{"Time":"2026-07-01T22:47:43.548736908+02:00","Action":"output","Package":"challenge","Output":"ok \tchallenge\t0.001s\n"}
{"Time":"2026-07-01T22:47:43.548749138+02:00","Action":"pass","Package":"challenge","Elapsed":0.001}