Skip to content

Commit 7e249c0

Browse files
authored
Merge pull request #1 from vatsalpatel/array_functions
Implement Array functions with tests
2 parents 91c44a7 + ff91810 commit 7e249c0

3 files changed

Lines changed: 1327 additions & 0 deletions

File tree

arrays.go

Lines changed: 339 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,339 @@
1+
package ut
2+
3+
import (
4+
"fmt"
5+
"math/rand"
6+
"time"
7+
)
8+
9+
// Chunk splits a slice into chunks of a specified size
10+
func Chunk[T any](arr []T, size int) [][]T {
11+
length := len(arr)
12+
if size <= 0 || length == 0 {
13+
return nil
14+
}
15+
16+
chunks := make([][]T, 0)
17+
for i := 0; i < length; i += size {
18+
end := i + size
19+
if end > length {
20+
end = length
21+
}
22+
chunks = append(chunks, arr[i:end])
23+
}
24+
25+
return chunks
26+
}
27+
28+
// Concat concatenates two or more slices into a single slice
29+
func Concat[T any](arrays ...[]T) []T {
30+
length := 0
31+
for _, arr := range arrays {
32+
length += len(arr)
33+
}
34+
35+
concatenated := make([]T, 0, length)
36+
for _, arr := range arrays {
37+
concatenated = append(concatenated, arr...)
38+
}
39+
40+
return concatenated
41+
}
42+
43+
// Difference creates a slice of values that are not in the other given slices
44+
func Difference[T comparable](arr []T, others ...[]T) []T {
45+
diffSet := make(map[T]struct{})
46+
for _, val := range arr {
47+
diffSet[val] = struct{}{}
48+
}
49+
50+
for _, other := range others {
51+
for _, val := range other {
52+
delete(diffSet, val)
53+
}
54+
}
55+
56+
difference := make([]T, 0, len(diffSet))
57+
for val := range diffSet {
58+
difference = append(difference, val)
59+
}
60+
61+
return difference
62+
}
63+
64+
// Every checks if all elements in the slice satisfy the given predicate.
65+
// The predicate is invoked with three arguments: (value, index, array).
66+
// It returns true if the predicate returns true for all elements, otherwise false.
67+
func Every[T any](arr []T, predicate func(T, int, []T) bool) bool {
68+
for i, value := range arr {
69+
if !predicate(value, i, arr) {
70+
return false
71+
}
72+
}
73+
return true
74+
}
75+
76+
// Fill modifies a slice by filling it with a specified value from a start index to an end index
77+
func Fill(arr []interface{}, value interface{}, start int, end int) {
78+
length := len(arr)
79+
if start < 0 {
80+
start = 0
81+
}
82+
if end > length {
83+
end = length
84+
}
85+
for i := start; i < end; i++ {
86+
arr[i] = value
87+
}
88+
}
89+
90+
// Filter filters the elements of a slice based on a predicate function.
91+
// The predicate function is invoked with three arguments: (value, index, arg),
92+
// and should return a boolean indicating whether the value should be included in the result.
93+
func Filter[T any](arr []T, predicate func(int, T, interface{}) bool, arg interface{}) []T {
94+
var result []T
95+
96+
for i, value := range arr {
97+
if predicate(i, value, arg) {
98+
result = append(result, value)
99+
}
100+
}
101+
102+
return result
103+
}
104+
105+
// FindIndex returns the index of the first element in a slice that satisfies the provided testing function
106+
func FindIndex(arr []interface{}, predicate func(interface{}) bool) int {
107+
for i, val := range arr {
108+
if predicate(val) {
109+
return i
110+
}
111+
}
112+
return -1
113+
}
114+
115+
// Flatten flattens a slice of slices into a single slice
116+
func Flatten(arr []interface{}) []interface{} {
117+
flattened := make([]interface{}, 0)
118+
for _, val := range arr {
119+
switch v := val.(type) {
120+
case []interface{}:
121+
flattened = append(flattened, Flatten(v)...)
122+
default:
123+
flattened = append(flattened, v)
124+
}
125+
}
126+
return flattened
127+
}
128+
129+
// Includes checks if a given value is present in the slice.
130+
// It returns true if the value is found, otherwise false.
131+
func Includes[T comparable](arr []T, value T) bool {
132+
for _, item := range arr {
133+
if item == value {
134+
return true
135+
}
136+
}
137+
return false
138+
}
139+
140+
// Intersection returns an array containing the unique values that are present in all of the input arrays.
141+
func Intersection(arrays ...[]interface{}) []interface{} {
142+
// Count occurrences of each element
143+
counts := make(map[interface{}]int)
144+
for _, arr := range arrays {
145+
seen := make(map[interface{}]bool)
146+
for _, elem := range arr {
147+
if !seen[elem] {
148+
counts[elem]++
149+
seen[elem] = true
150+
}
151+
}
152+
}
153+
154+
// Filter elements that appear in all arrays
155+
var result []interface{}
156+
for elem, count := range counts {
157+
if count == len(arrays) {
158+
result = append(result, elem)
159+
}
160+
}
161+
162+
return result
163+
}
164+
165+
// Join concatenates all elements of an array into a single string using the provided separator.
166+
func Join(arr []interface{}, separator string) string {
167+
if len(arr) == 0 {
168+
return ""
169+
}
170+
171+
var result string
172+
for i, elem := range arr {
173+
if i > 0 {
174+
result += separator
175+
}
176+
result += fmt.Sprintf("%v", elem)
177+
}
178+
179+
return result
180+
}
181+
182+
// Map applies a transformation function to each element of the input array/slice
183+
// and returns a new array/slice with the transformed values.
184+
func Map[T any, U any](arr []T, transformFunc func(int, T, interface{}) U, arg interface{}) []U {
185+
result := make([]U, len(arr))
186+
187+
for i, element := range arr {
188+
transformedValue := transformFunc(i, element, arg)
189+
result[i] = transformedValue
190+
}
191+
192+
return result
193+
}
194+
195+
// Pull removes all occurrences of the specified values from a slice.
196+
func Pull[T comparable](arr []T, values ...T) []T {
197+
var result []T
198+
excluded := make(map[T]struct{})
199+
200+
for _, value := range values {
201+
excluded[value] = struct{}{}
202+
}
203+
204+
for _, item := range arr {
205+
if _, excluded := excluded[item]; !excluded {
206+
result = append(result, item)
207+
}
208+
}
209+
210+
return result
211+
}
212+
213+
// Reduce applies a function against an accumulator and each element in the slice (from left to right)
214+
// to reduce it to a single value.
215+
// The transform function is invoked with four arguments: (accumulator, value, index, arg).
216+
// The initial value of the accumulator is provided as the initialValue parameter.
217+
func Reduce[T any, R any](arr []T, transform func(R, T, int, interface{}) R, initialValue R, arg interface{}) R {
218+
accumulator := initialValue
219+
220+
for i, value := range arr {
221+
accumulator = transform(accumulator, value, i, arg)
222+
}
223+
224+
return accumulator
225+
}
226+
227+
// Remove removes all elements from the slice for which the predicate returns truthy,
228+
// and returns an array of the removed elements.
229+
// The predicate is invoked with three arguments: (value, index, array).
230+
func Remove[T any](arr *[]T, predicate func(T, int, []T) bool) []T {
231+
var removed []T
232+
remaining := (*arr)[:0]
233+
234+
for index, value := range *arr {
235+
if predicate(value, index, *arr) {
236+
removed = append(removed, value)
237+
} else {
238+
remaining = append(remaining, value)
239+
}
240+
}
241+
242+
*arr = remaining
243+
return removed
244+
}
245+
246+
// Reverse reverses the elements of a slice in place
247+
func Reverse[T any](arr []T) {
248+
for i, j := 0, len(arr)-1; i < j; i, j = i+1, j-1 {
249+
arr[i], arr[j] = arr[j], arr[i]
250+
}
251+
}
252+
253+
// Shuffle shuffles the elements of the slice using the Fisher-Yates algorithm. It modifies the input slice in place.
254+
func Shuffle[T any](arr []T) {
255+
r := rand.New(rand.NewSource(time.Now().UnixNano()))
256+
for i := len(arr) - 1; i > 0; i-- {
257+
j := r.Intn(i + 1)
258+
arr[i], arr[j] = arr[j], arr[i]
259+
}
260+
}
261+
262+
// Slice returns a portion of a slice from a start index to an end index
263+
func Slice[T any](arr []T, start, end int) []T {
264+
if start < 0 {
265+
start = 0
266+
}
267+
if end > len(arr) {
268+
end = len(arr)
269+
}
270+
if start > end {
271+
return nil
272+
}
273+
return arr[start:end]
274+
}
275+
276+
// Some checks if at least one element in the slice satisfies the given predicate.
277+
// The predicate is invoked with three arguments: (value, index, array).
278+
// It returns true if the predicate returns true for any element, otherwise false.
279+
func Some[T any](arr []T, predicate func(T, int, []T) bool) bool {
280+
for i, value := range arr {
281+
if predicate(value, i, arr) {
282+
return true
283+
}
284+
}
285+
return false
286+
}
287+
288+
// Union returns a new slice that contains the unique elements from all input slices.
289+
// The order of elements in the resulting slice is undefined.
290+
func Union[T comparable](slices ...[]T) []T {
291+
// Use a map to track unique elements
292+
uniqueElements := make(map[T]struct{})
293+
294+
for _, slice := range slices {
295+
for _, elem := range slice {
296+
uniqueElements[elem] = struct{}{}
297+
}
298+
}
299+
300+
// Build the resulting slice from the unique elements
301+
result := make([]T, 0, len(uniqueElements))
302+
for elem := range uniqueElements {
303+
result = append(result, elem)
304+
}
305+
306+
return result
307+
}
308+
309+
// Uniq creates a new slice of unique values in the order of their first occurrence in the original slice
310+
func Uniq[T comparable](arr []T) []T {
311+
seen := make(map[T]struct{})
312+
var result []T
313+
314+
for _, value := range arr {
315+
if _, exists := seen[value]; !exists {
316+
seen[value] = struct{}{}
317+
result = append(result, value)
318+
}
319+
}
320+
321+
return result
322+
}
323+
324+
// Zip merges multiple slices into a single slice of tuples, where each tuple contains
325+
// the corresponding elements from each of the input slices.
326+
// The length of the resulting slice is determined by the shortest input slice.
327+
func Zip[T1, T2 interface{}](slice1 []T1, slice2 []T2) [][]interface{} {
328+
length := len(slice1)
329+
if len(slice2) < length {
330+
length = len(slice2)
331+
}
332+
333+
zipped := make([][]interface{}, length)
334+
for i := 0; i < length; i++ {
335+
zipped[i] = []interface{}{slice1[i], slice2[i]}
336+
}
337+
338+
return zipped
339+
}

0 commit comments

Comments
 (0)