Skip to content

Commit a3f3b18

Browse files
authored
Add solutions by odelbos (#64)
* Add solution for Challenge 27 by odelbos * Add solution for Challenge 9 by odelbos
1 parent f6dd080 commit a3f3b18

File tree

2 files changed

+609
-0
lines changed

2 files changed

+609
-0
lines changed
Lines changed: 269 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,269 @@
1+
package generics
2+
3+
import (
4+
"errors"
5+
"slices"
6+
)
7+
8+
// ErrEmptyCollection is returned when an operation cannot be performed on an empty collection
9+
var ErrEmptyCollection = errors.New("collection is empty")
10+
11+
//
12+
// 1. Generic Pair
13+
//
14+
15+
// Pair represents a generic pair of values of potentially different types
16+
type Pair[T, U any] struct {
17+
First T
18+
Second U
19+
}
20+
21+
// NewPair creates a new pair with the given values
22+
func NewPair[T, U any](first T, second U) Pair[T, U] {
23+
return Pair[T, U]{First: first, Second: second}
24+
}
25+
26+
// Swap returns a new pair with the elements swapped
27+
func (p Pair[T, U]) Swap() Pair[U, T] {
28+
return Pair[U, T]{First: p.Second, Second: p.First}
29+
}
30+
31+
//
32+
// 2. Generic Stack
33+
//
34+
35+
// Stack is a generic Last-In-First-Out (LIFO) data structure
36+
type Stack[T any] struct {
37+
items []T
38+
}
39+
40+
// NewStack creates a new empty stack
41+
func NewStack[T any]() *Stack[T] {
42+
return &Stack[T]{items: make([]T, 0)}
43+
}
44+
45+
// Push adds an element to the top of the stack
46+
func (s *Stack[T]) Push(value T) {
47+
s.items = append(s.items, value)
48+
}
49+
50+
// Pop removes and returns the top element from the stack
51+
// Returns an error if the stack is empty
52+
func (s *Stack[T]) Pop() (T, error) {
53+
if s.IsEmpty() {
54+
var zero T
55+
return zero, ErrEmptyCollection
56+
}
57+
idx := len(s.items) - 1
58+
val := s.items[idx]
59+
s.items = s.items[:idx]
60+
return val, nil
61+
}
62+
63+
// Peek returns the top element without removing it
64+
// Returns an error if the stack is empty
65+
func (s *Stack[T]) Peek() (T, error) {
66+
if s.IsEmpty() {
67+
var zero T
68+
return zero, ErrEmptyCollection
69+
}
70+
return s.items[len(s.items)-1], nil
71+
}
72+
73+
// Size returns the number of elements in the stack
74+
func (s *Stack[T]) Size() int {
75+
return len(s.items)
76+
}
77+
78+
// IsEmpty returns true if the stack contains no elements
79+
func (s *Stack[T]) IsEmpty() bool {
80+
return len(s.items) == 0
81+
}
82+
83+
//
84+
// 3. Generic Queue
85+
//
86+
87+
// Queue is a generic First-In-First-Out (FIFO) data structure
88+
type Queue[T any] struct {
89+
items []T
90+
}
91+
92+
// NewQueue creates a new empty queue
93+
func NewQueue[T any]() *Queue[T] {
94+
return &Queue[T]{items: make([]T, 0)}
95+
}
96+
97+
// Enqueue adds an element to the end of the queue
98+
func (q *Queue[T]) Enqueue(value T) {
99+
q.items = append(q.items, value)
100+
}
101+
102+
// Dequeue removes and returns the front element from the queue
103+
// Returns an error if the queue is empty
104+
func (q *Queue[T]) Dequeue() (T, error) {
105+
if q.IsEmpty() {
106+
var zero T
107+
return zero, ErrEmptyCollection
108+
}
109+
val := q.items[0]
110+
q.items = q.items[1:]
111+
return val, nil
112+
}
113+
114+
// Front returns the front element without removing it
115+
// Returns an error if the queue is empty
116+
func (q *Queue[T]) Front() (T, error) {
117+
if q.IsEmpty() {
118+
var zero T
119+
return zero, ErrEmptyCollection
120+
}
121+
return q.items[0], nil
122+
}
123+
124+
// Size returns the number of elements in the queue
125+
func (q *Queue[T]) Size() int {
126+
return len(q.items)
127+
}
128+
129+
// IsEmpty returns true if the queue contains no elements
130+
func (q *Queue[T]) IsEmpty() bool {
131+
return len(q.items) == 0
132+
}
133+
134+
//
135+
// 4. Generic Set
136+
//
137+
138+
// Set is a generic collection of unique elements
139+
type Set[T comparable] struct {
140+
items map[T]struct{}
141+
}
142+
143+
// NewSet creates a new empty set
144+
func NewSet[T comparable]() *Set[T] {
145+
return &Set[T]{items: make(map[T]struct{})}
146+
}
147+
148+
// Add adds an element to the set if it's not already present
149+
func (s *Set[T]) Add(value T) {
150+
s.items[value] = struct{}{}
151+
}
152+
153+
// Remove removes an element from the set if it exists
154+
func (s *Set[T]) Remove(value T) {
155+
delete(s.items, value)
156+
}
157+
158+
// Contains returns true if the set contains the given element
159+
func (s *Set[T]) Contains(value T) bool {
160+
_, ok := s.items[value]
161+
return ok
162+
}
163+
164+
// Size returns the number of elements in the set
165+
func (s *Set[T]) Size() int {
166+
return len(s.items)
167+
}
168+
169+
// Elements returns a slice containing all elements in the set
170+
func (s *Set[T]) Elements() []T {
171+
result := make([]T, 0, len(s.items))
172+
for val := range(s.items) {
173+
result = append(result, val)
174+
}
175+
return result
176+
}
177+
178+
// Union returns a new set containing all elements from both sets
179+
func Union[T comparable](s1, s2 *Set[T]) *Set[T] {
180+
result := NewSet[T]()
181+
for val := range(s1.items) {
182+
result.Add(val)
183+
}
184+
for val := range(s2.items) {
185+
result.Add(val)
186+
}
187+
return result
188+
}
189+
190+
// Intersection returns a new set containing only elements that exist in both sets
191+
func Intersection[T comparable](s1, s2 *Set[T]) *Set[T] {
192+
result := NewSet[T]()
193+
for val := range(s1.items) {
194+
if s2.Contains(val) {
195+
result.Add(val)
196+
}
197+
}
198+
return result
199+
}
200+
201+
// Difference returns a new set with elements in s1 that are not in s2
202+
func Difference[T comparable](s1, s2 *Set[T]) *Set[T] {
203+
result := NewSet[T]()
204+
for val := range(s1.items) {
205+
if ! s2.Contains(val) {
206+
result.Add(val)
207+
}
208+
}
209+
return result
210+
}
211+
212+
//
213+
// 5. Generic Utility Functions
214+
//
215+
216+
// Filter returns a new slice containing only the elements for which the predicate returns true
217+
func Filter[T any](slice []T, predicate func(T) bool) []T {
218+
result := make([]T, 0)
219+
for _, val := range(slice) {
220+
if predicate(val) {
221+
result = append(result, val)
222+
}
223+
}
224+
return result
225+
}
226+
227+
// Map applies a function to each element in a slice and returns a new slice with the results
228+
func Map[T, U any](slice []T, mapper func(T) U) []U {
229+
result := make([]U, len(slice))
230+
for i, val := range(slice) {
231+
result[i] = mapper(val)
232+
}
233+
return result
234+
}
235+
236+
// Reduce reduces a slice to a single value by applying a function to each element
237+
func Reduce[T, U any](slice []T, initial U, reducer func(U, T) U) U {
238+
result := initial
239+
for _, val := range(slice) {
240+
result = reducer(result, val)
241+
}
242+
return result
243+
}
244+
245+
// Contains returns true if the slice contains the given element
246+
func Contains[T comparable](slice []T, element T) bool {
247+
return slices.Contains(slice, element)
248+
}
249+
250+
// FindIndex returns the index of the first occurrence of the given element or -1 if not found
251+
func FindIndex[T comparable](slice []T, element T) int {
252+
for i, val := range(slice) {
253+
if val == element {
254+
return i
255+
}
256+
}
257+
return -1
258+
}
259+
260+
// RemoveDuplicates returns a new slice with duplicate elements removed, preserving order
261+
func RemoveDuplicates[T comparable](slice []T) []T {
262+
result := make([]T, 0)
263+
for _, val := range(slice) {
264+
if ! slices.Contains(result, val) {
265+
result = append(result, val)
266+
}
267+
}
268+
return result
269+
}

0 commit comments

Comments
 (0)