Skip to content

Instantly share code, notes, and snippets.

@johnwesonga
Created August 22, 2013 00:29
Show Gist options
  • Save johnwesonga/6301924 to your computer and use it in GitHub Desktop.
Save johnwesonga/6301924 to your computer and use it in GitHub Desktop.
Go code that ensures elements in a slice are unique
package main
import "fmt"
func uniqueNonEmptyElementsOf(s []string) []string {
unique := make(map[string]bool, len(s))
us := make([]string, len(unique))
for _, elem := range s {
if len(elem) != 0 {
if !unique[elem] {
us = append(us, elem)
unique[elem] = true
}
}
}
return us
}
func main() {
names := []string{"John", "Peter", "Jim", "John", "Ken", "Pete", "Jimmy"}
fmt.Println(uniqueNonEmptyElementsOf(names))
}
@BryceWayne
Copy link

Thanks! Need this. You create a map for fast look up and take only unique elements.

@ramonfincken
Copy link

Agreed! All other examples were merely integer based, not strings

@cr1cr1
Copy link

cr1cr1 commented Sep 26, 2023

func UniqueSliceElements[T comparable](inputSlice []T) []T {
	uniqueSlice := make([]T, 0, len(inputSlice))
	seen := make(map[T]bool, len(inputSlice))
	for _, element := range inputSlice {
		if !seen[element] {
			uniqueSlice = append(uniqueSlice, element)
			seen[element] = true
		}
	}
	return uniqueSlice
}

@Demznak
Copy link

Demznak commented Oct 11, 2023

func UniqueSliceElements[T comparable](inputSlice []T) []T {
	uniqueSlice := make([]T, 0, len(inputSlice))
	seen := make(map[T]struct{}, len(inputSlice))
	for _, element := range inputSlice {
		if !seen[element] {
			uniqueSlice = append(uniqueSlice, element)
			seen[element] = struct{}{}
		}
	}
	return uniqueSlice
}

@cr1cr1
Copy link

cr1cr1 commented Oct 11, 2023

@Demznak 👍 for smaller memory footprint :)

the seen test probably should be if _, ok := seen[element]; !ok {

@cr1cr1
Copy link

cr1cr1 commented Oct 11, 2023

Just as an experiment...

package main

import (
	"fmt"
	"math/rand"
	"testing"
)

var inputSlice []int

func UniqueSliceElementsStruct[T comparable](inputSlice []T) []T {
	uniqueSlice := make([]T, 0, len(inputSlice))
	seen := make(map[T]struct{}, len(inputSlice))
	for _, element := range inputSlice {
		if _, ok := seen[element]; !ok {
			uniqueSlice = append(uniqueSlice, element)
			seen[element] = struct{}{}
		}
	}
	return uniqueSlice
}

func UniqueSliceElementsBool[T comparable](inputSlice []T) []T {
	uniqueSlice := make([]T, 0, len(inputSlice))
	seen := make(map[T]bool, len(inputSlice))
	for _, element := range inputSlice {
		if !seen[element] {
			uniqueSlice = append(uniqueSlice, element)
			seen[element] = true
		}
	}
	return uniqueSlice
}

func BenchmarkUniqueSliceElementsStruct(b *testing.B) {
	b.N = 10000
	for i := 0; i < b.N; i++ {
		UniqueSliceElementsStruct(inputSlice)
	}
}

func BenchmarkUniqueSliceElementsBool(b *testing.B) {
	b.N = 10000
	for i := 0; i < b.N; i++ {
		UniqueSliceElementsBool(inputSlice)
	}
}

type BenchResult struct {
	name   string
	result testing.BenchmarkResult
}

func main() {
	// Generate a slice
	inputSlice = make([]int, 100000)

	// Fill the slice with random integers between 0 and 999
	for i := range inputSlice {
		inputSlice[i] = rand.Intn(1000)
	}

	results := []BenchResult{
		{
			name:   "BenchmarkUniqueSliceElementsStruct",
			result: testing.Benchmark(BenchmarkUniqueSliceElementsStruct),
		},
		{
			name:   "BenchmarkUniqueSliceElementsBool",
			result: testing.Benchmark(BenchmarkUniqueSliceElementsBool),
		},
	}

	fmt.Printf("%-*s | ", 35, "Bench")
	fmt.Printf("%-*s | ", 9, "Mem alloc")
	fmt.Printf("%-*s | ", 12, "Bytes alloc")
	fmt.Printf("%-*s | ", 9, "Runs")
	fmt.Printf("%-*s", 9, "Time")
	fmt.Println()
	for i := 0; i < len(results); i++ {
		fmt.Printf("%-*s | ", 35, results[i].name)
		fmt.Printf("%-*d | ", 9, results[i].result.MemAllocs)
		fmt.Printf("%-*d | ", 12, results[i].result.Bytes)
		fmt.Printf("%-*d | ", 9, results[i].result.N)
		fmt.Printf("%-*s", 9, results[i].result.T)
		fmt.Println()
	}
}

go run main.go

Bench                               | Mem alloc | Bytes alloc  | Runs      | Time
BenchmarkUniqueSliceElementsStruct  | 30618     | 0            | 10000     | 7.3797462s
BenchmarkUniqueSliceElementsBool    | 30612     | 0            | 10000     | 7.1591373s

@Demznak
Copy link

Demznak commented Dec 21, 2023

@cr1cr1 The experiment was interesting Ж)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment