[GO] Some Slice helper functions using Generic
Ngoc Phuong
Ngoc Phuong
1424 views1 comments

[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

Discussion (1)

Daao888  June 2, 2022 01:23 UTC

Very Good !

LoginRegisterTopics