SoFunction
Updated on 2025-04-11

Detailed explanation of how to efficiently process collections in Go

In Go, although there is no traditional collection framework like Java or Python, collection operations can be handled very efficiently through built-in data structures (such as arrays, slices, maps), interfaces, and some standard library tools. With the introduction of generics in Go 1.18, collection operations have become more flexible and scalable.

There are usually several ways to process collections in Go:

  • Arrays and slices: Suitable for ordered collections.
  • Map: Applicable to key-value pair collections, often used for search, deduplication and other operations.
  • Structure and interface: Used to create custom collection types.

Next, we will explain how to use these built-in data structures and generics to efficiently process collections and give code examples.

1. Slice

Slicing is the most commonly used data structure in Go language. It is a dynamic array based on arrays, which can flexibly add and delete elements. You can use slices to simulate most collection operations.

Example: Deduplication

package main

import (
	"fmt"
)

func removeDuplicates(input []int) []int {
	unique := make([]int, 0, len(input))
	seen := make(map[int]struct{})
	for _, value := range input {
		if _, ok := seen[value]; !ok {
			unique = append(unique, value)
			seen[value] = struct{}{}
		}
	}
	return unique
}

func main() {
	input := []int{1, 2, 3, 3, 4, 5, 5, 6}
	unique := removeDuplicates(input)
	("Unique elements:", unique)
}

illustrate:

Use map to record elements that have appeared, and this way removes duplicate elements from the slice.

The time complexity of this operation is O(n), where n is the length of the input slice.

2. Mapping (Map)

Go's map is a hash table implementation suitable for handling collections of key-value pairs. It is often used for search, deduplication, and counting frequency.

Example: Statistical word frequency

package main

import (
	"fmt"
	"strings"
)

func countWords(text string) map[string]int {
	wordCount := make(map[string]int)
	words := (text)
	for _, word := range words {
		wordCount[word]++
	}
	return wordCount
}

func main() {
	text := "go is awesome go is fast"
	count := countWords(text)
	("Word Count:", count)
}

illustrate:

  • map[string]int is used to store each word and its occurrence number.
  • () is used to split the input text into words.

3. Custom collection type (struct + interface)

The Go language supports creating custom collection types through structures and interfaces. In some cases, using custom structure collections can bring more flexibility.

Example: Custom collection type

package main

import (
	"fmt"
)

type IntSet struct {
	set map[int]struct{}
}

// Create a new IntSet collectionfunc NewIntSet() *IntSet {
	return &IntSet{set: make(map[int]struct{})}
}

// Add elements to the collectionfunc (s *IntSet) Add(value int) {
	[value] = struct{}{}
}

// Determine whether the set contains an elementfunc (s *IntSet) Contains(value int) bool {
	_, exists := [value]
	return exists
}

// Remove elements from the collectionfunc (s *IntSet) Remove(value int) {
	delete(, value)
}

// Print collectionfunc (s *IntSet) Print() {
	for value := range  {
		(value)
	}
}

func main() {
	set := NewIntSet()
	(1)
	(2)
	(3)

	("Contains 2:", (2)) // true
	(2)
	("Contains 2:", (2)) // false

	("Set contents:")
	() // 1 3
}

illustrate:

  • IntSet is a custom collection type encapsulated by map[int]struct{}, providing methods for collection operations (add, delete, and search).
  • Use map to store collection elements and use an empty struct (struct{}) to optimize memory footprint.

4. Use generics to process collections (Go 1.18+)

Go 1.18 introduces generics, greatly enhancing the flexibility and type safety of handling collections. Generics allow you to create collections that can handle multiple data types.

Example: Implementing a general collection using generics

package main

import (
	"fmt"
)

// Generic collectionstype Set[T comparable] struct {
	items map[T]struct{}
}

// Create a new collectionfunc NewSet[T comparable]() *Set[T] {
	return &Set[T]{items: make(map[T]struct{})}
}

// Add elements to the collectionfunc (s *Set[T]) Add(value T) {
	[value] = struct{}{}
}

// Determine whether the set contains an elementfunc (s *Set[T]) Contains(value T) bool {
	_, exists := [value]
	return exists
}

// Print collectionfunc (s *Set[T]) Print() {
	for value := range  {
		(value)
	}
}

func main() {
	// Integer collection	intSet := NewSet[int]()
	(1)
	(2)
	(3)
	("Integer Set:")
	()

	// String collection	strSet := NewSet[string]()
	("apple")
	("banana")
	("cherry")
	("String Set:")
	()
}

illustrate:

Generic Set[T comparable] can handle collections of any type.

The T comparable constraint means that the generic type T must be comparable (i.e., it can be compared with the == or != operator).

5. Concurrent collection

Go supports efficient concurrent programming, so you can use Go's concurrency features to create thread-safe collections. In a high concurrency environment, use or to protect the read and write operations of the collection.

Example: Concurrently secure collection

package main

import (
	"fmt"
	"sync"
)

type ConcurrentSet struct {
	set  map[int]struct{}
	lock 
}

func NewConcurrentSet() *ConcurrentSet {
	return &ConcurrentSet{
		set: make(map[int]struct{}),
	}
}

func (s *ConcurrentSet) Add(value int) {
	()
	defer ()
	[value] = struct{}{}
}

func (s *ConcurrentSet) Contains(value int) bool {
	()
	defer ()
	_, exists := [value]
	return exists
}

func (s *ConcurrentSet) Remove(value int) {
	()
	defer ()
	delete(, value)
}

func main() {
	cs := NewConcurrentSet()

	// Use goroutine to access the collection concurrently	var wg 
	for i := 0; i < 10; i++ {
		(1)
		go func(i int) {
			defer ()
			(i)
			("Added", i)
		}(i)
	}
	()

	// View collection content	for i := 0; i < 10; i++ {
		if (i) {
			("Contains", i)
		}
	}
}

illustrate:

Use to allow multiple read operations to be performed simultaneously, while write operations are exclusive, which can improve concurrency performance.

In concurrent scenarios, access to the collection is protected in a mutex lock to ensure thread safety.

Summarize

Slicing and Mapping: is the most commonly used collection type in Go, suitable for ordered data and key-value pair storage, respectively.

Custom collections: Flexible collection types can be created through structures and interfaces to meet more complex needs.

Generic Collections: Generics introduced in Go 1.18 make collection operations more flexible, can handle multiple data types, and avoid type casting.

Concurrent collection: In high concurrency scenarios, the thread safety of the collection can be used or can be ensured.

By combining these technologies, you can handle various collection operations in the Go language very efficiently and flexibly.

This is the end of this article about how to efficiently process collections in Go. For more relevant Go collection content, please search for my previous articles or continue browsing the related articles below. I hope everyone will support me in the future!