![[GO] Some Slice helper functions using Generic](https://cdn.tetua.net/files/2022/05/1652503570381775_golang-generic-slice.png)
[GO] Some Slice helper functions using Generic
When developing application with Golang, i sometime have to write helper functions for that working with slice. There are common functions that i use frequence as:
- Check if slice contain an element
- Filter out slice element that match some condition
- Map a slice to a diffrence type
It was a common case that i have to rewrite every helper for difference type of data, and it’s so annoy.
With the recent version 18 of Go, i decided to rewrite the common slice function with the help of Generic. As an expected result, generic work good and help me avoid the redundant/dry code.
Here are some slice helper functions that i want to share:
Contains: Check if a slice contain an element
func Contains[T comparable](slice []T, element T) bool {
	for _, e := range slice {
		if e == element {
			return true
		}
	}
	return false
}
Usage
var stringSlice = []string{"item 1", "item 2"}
var intSlice = []int{1, 2, 3}
fmt.Println(Contains(stringSlice, "item 2")) // true
fmt.Println(Contains(intSlice, 4)) // false
Filter: Filter a slice to return only the elements that match a condition
func Filter[T comparable](slice []T, predicate func(T) bool) []T {
	var result []T
	for _, e := range slice {
		if predicate(e) {
			result = append(result, e)
		}
	}
	return result
}
Usage
var intSlice = []int{1, 2, 3, 4, 5, 6, 7, 8, 9}
var oddSlice = Filter(intSlice, func(element int) bool {
    return element % 2 != 0
})
fmt.Println(oddSlice) // []int{1, 3, 5, 7, 9}
Map: Transform a slice into a diffrence slice type
func Map[T comparable, R comparable](slice []T, mapper func(T) R) []R {
	var result []R
	for _, e := range slice {
		result = append(result, mapper(e))
	}
	return result
}
Usage
var intSlice = []int{1, 2, 3}
var strSlice = Map(intSlice, func(element int) string {
    return strconv.Itoa(element)
})
fmt.Println(strSlice) // []string{"1", "2", "3"}
Repeat: Create a slice with a repeated values
func Repeat[T comparable](input T, time int) []T {
	var result []T
	var i = 0
	for i < time {
		result = append(result, input)
		i++
	}
	return result
}
Usage
var intSlice = Repeat(1, 3)
fmt.Println(intSlice) // []int{1, 1, 1}
Overlap: Get the overlap elements beetween two slice
func Overlap[T comparable](slice1 []T, slice2 []T) []T {
	result := make([]T, 0)
	for _, e1 := range slice1 {
		if SliceContains(slice2, e1) {
			result = append(result, e1)
		}
	}
	return result
}
Usage
var slice1 = []int{1, 2, 3}
var slice2 = []int{2, 3, 4}
var result = Overlap(slice1, slice2)
fmt.Println(result) // []int{2, 3}
AppendIfNotExists: Append an element to a slice only if it isn’t existed
func AppendIfNotExists[T comparable](slice []T, newItem T) []T {
	for _, s := range slice {
		if s == newItem {
			return slice
		}
	}
	return append(slice, newItem)
}
Usage
var intSlice = []int{1, 2, 3}
var intSlice1 = AppendIfNotExists(intSlice, 3)
var intSlice2 = AppendIfNotExists(intSlice, 4)
fmt.Println(intSlice1) // []int{1, 2, 3}
fmt.Println(intSlice2) // []int{1, 2, 3, 4}
Some time you may want to append an item to a slice only if a certain condition is matched or the Type is not comparable, you can modify the AppendIfNotExists as bellow:
func AppendIfNotExists[T any](slice []T, newItem T, checkExists func(T) bool) []T {
	for _, s := range slice {
		if checkExists(s) {
			return slice
		}
	}
	return append(slice, newItem)
}
Usage
type Thing struct {
    ID int
    Name string
}
var things = []Thing{
	{ID: 1, Name: "one"},
	{ID: 2, Name: "two"},
}
var thing3 = Thing{ID: 3, "three"}
var thing2 = Thing{ID: 2, Name: "Thing 2"}
var thingSlice1 = AppendIfNotExists(things, thing2, func (element Thing) bool {
    return element.ID == thing2.ID
})
var thingSlice2 = AppendIfNotExists(things, thing3, func (element Thing) bool {
    return element.ID == thing3.ID
})
fmt.Println(len(thingSlice1)) // 2
fmt.Println(len(thingSlice2)) // 3
Very Good !