Golang hash sets implementation in 2 simple ways

Mani
Mani
Educating everyone with the beauty of programming!!
Golang hash sets implementation in 2 simple ways

2 Simple ways to implement hashset in go

Exploring Set Data Structures in Go

Introduction to the Go Language and Data Structures

The Go programming language, often referred to as Golang, has gained immense popularity in the software development industry. Known for its efficiency, simplicity, and speed, Go has become a top choice for building a wide range of applications, from web services to system-level software.

In any programming language, data structures play a crucial role in optimizing code. They provide a means to organize and manipulate data efficiently. In this blog post, we will delve into one particular data structure in Go that is both powerful and versatile - the set data structure.

In case you missed it check out other Golang articles here

3 simple ways to get the first character of a string in Golang

Golang read file line by line - 3 Simple ways

Golang enums implementation with examples

Golang for loops: 5 basic ways with examples using range, arrays, maps iteration

Golang get last element of slice / array / list - Simple and fast

Golang get map keys - 3 Simple ways

What is a Set Data Structure?

Before we dive into Go’s implementation, let’s understand what a set data structure is. In computer science, a set is a collection of distinct elements with no specific order. This uniqueness of elements is a fundamental characteristic of sets. Sets do not allow duplicate values, making them ideal for scenarios where you need to store a unique collection of items.

Go’s Set Data Structure

Go doesn’t have a built-in set data structure in its standard library like some other languages do. However, it’s relatively easy to implement sets in Go using slices or maps.

Method 1. Implementing a Set Using a Map

You can create a simple set in Go by using a map with a boolean value for each element. Here’s an example:

1
2
3
4
5
6
7
8
set := make(map[string]bool)
set["apple"] = true
set["banana"] = true

// Check if an element is in the set
if set["apple"] {
    fmt.Println("Apple is in the set.")
}

Example 1: Simple example for Set in GoLang

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
package main

import "fmt"

func main() {
    // Initialize a set as a map with boolean values
    mySet := make(map[string]bool)

    // Add elements to the set
    mySet["apple"] = true
    mySet["banana"] = true
    mySet["cherry"] = true

    // Lookup elements in the set
    elementToLookup := "banana"
    if mySet[elementToLookup] {
        fmt.Printf("%s exists in the set.\n", elementToLookup)
    } else {
        fmt.Printf("%s does not exist in the set.\n", elementToLookup)
    }

    // Another lookup
    elementToLookup = "grape"
    if mySet[elementToLookup] {
        fmt.Printf("%s exists in the set.\n", elementToLookup)
    } else {
        fmt.Printf("%s does not exist in the set.\n", elementToLookup)
    }
}
1
2
3
Output:
banana exists in the set.
grape does not exist in the set.

In this simplified example, we use a map to represent a set of strings. We add elements to the set by setting the corresponding map values to true. To look up an element, we check whether the element is present in the map by accessing it with square brackets and checking the boolean value.

Example 2: Implementing all Set methods in Golang example

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
package main

import "fmt"

// Define a Set type as a map with a boolean value
type Set map[string]bool

// Function to add an element to the set
func (set Set) Add(element string) {
	set[element] = true
}

// Function to remove an element from the set
func (set Set) Remove(element string) {
	delete(set, element)
}

// Function to check if an element exists in the set
func (set Set) Contains(element string) bool {
	return set[element]
}

// Function to get the size of the set
func (set Set) Size() int {
	return len(set)
}

func main() {
    // Initialize a new set
	mySet := make(Set)

	// Add elements to the set
	mySet.Add("apple")
	mySet.Add("banana")
	mySet.Add("cherry")

	// Check if an element exists in the set
	fmt.Println("Does 'apple' exist in the set?", mySet.Contains("apple")) // Should print true
	fmt.Println("Does 'grape' exist in the set?", mySet.Contains("grape")) // Should print false

	// Remove an element from the set
	mySet.Remove("banana")

	// Check the size of the set
	fmt.Println("Size of the set:", mySet.Size()) // Should print 2

	// List all elements in the set
	fmt.Println("Elements in the set:")
	for element := range mySet {
		fmt.Println(element)
	}
}

1
2
3
4
5
6
7
8
Output: 

Does 'apple' exist in the set? true
Does 'grape' exist in the set? false
Size of the set: 2
Elements in the set:
apple
cherry

In this example, we define a Set type as a map where the keys are of type string, and the values are of type bool. This allows us to represent a set where each element is a unique string. The Add, Remove, and Contains methods are defined to manipulate the set, and the Size method returns the size of the set.

This code snippet demonstrates how to implement a basic set using a map. Each element is associated with a boolean value, indicating its presence or absence in the set.

Method 2: Using a Slice for a Set

Alternatively, you can use a slice to implement a set. The uniqueness of elements can be enforced by iterating through the slice and checking for duplicates before adding an element.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
set := []string{}
element := "apple"

// Check if the element is already in the set
found := false
for _, item := range set {
    if item == element {
        found = true
        break
    }
}

// Add the element if not found
if !found {
    set = append(set, element)
}

Example 3: Set implementation using slices

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
package main

import "fmt"

// Define a Set type as a slice of strings
type Set []string

// Function to add an element to the set
func (set *Set) Add(element string) {
    for _, existingElement := range *set {
        if existingElement == element {
            return // Element already exists, no need to add it again
        }
    }
    *set = append(*set, element)
}

// Function to check if an element exists in the set
func (set Set) Contains(element string) bool {
    for _, existingElement := range set {
        if existingElement == element {
            return true
        }
    }
    return false
}

func main() {
    // Initialize a new set
    var mySet Set

    // Add elements to the set
    mySet.Add("apple")
    mySet.Add("banana")
    mySet.Add("cherry")

    // Lookup elements in the set
    elementToLookup := "banana"
    if mySet.Contains(elementToLookup) {
        fmt.Printf("%s exists in the set.\n", elementToLookup)
    } else {
        fmt.Printf("%s does not exist in the set.\n", elementToLookup)
    }

    // Another lookup
    elementToLookup = "grape"
    if mySet.Contains(elementToLookup) {
        fmt.Printf("%s exists in the set.\n", elementToLookup)
    } else {
        fmt.Printf("%s does not exist in the set.\n", elementToLookup)
    }
}

1
2
3
Output: 
banana exists in the set.
grape does not exist in the set.

This approach requires a bit more code to maintain uniqueness, but it can be useful for situations where you want more control over the set’s behavior.

Use Cases for Sets in Go

Sets in Go are valuable in various practical scenarios. Here are some examples of real-world problems that can be solved more efficiently using sets:

Deduplication

When dealing with data streams or collections where duplicates can occur, sets are invaluable for eliminating redundancy. For instance, when processing user-generated content, you can use a set to ensure that no duplicate entries are saved.

Membership Testing

Sets are perfect for membership testing. You can quickly check if an element belongs to a particular set, which is useful in permission management or access control systems.

Counting Unique Items

Counting unique items in a large dataset becomes much more efficient with sets. For example, you might want to count the number of unique visitors to a website.

Advantages of Using Sets in Go

Utilizing sets in Go applications offers several advantages:

Fast Lookup

Sets allow for extremely fast membership tests. Whether you use a map or a slice, the time complexity for looking up an element is O(1), making them exceptionally efficient.

Automatic Duplicate Elimination

By design, sets do not allow duplicates. This automatic deduplication simplifies your code and ensures data integrity.

Improved Code Readability

Using sets can make your code more readable and maintainable, especially in scenarios where you need to manage unique elements.

Working with Sets in Go

Let’s explore how to work with sets in Go by providing code examples.

Adding an Element to the Set

To add an element to a set implemented as a map, simply set the corresponding value to true.

1
2
set := make(map[string]bool)
set["apple"] = true

When using a slice, you can add an element like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
set := []string{}
element := "apple"

// Check if the element is already in the set
found := false
for _, item := range set {
    if item == element {
        found = true
        break
    }
}

// Add the element if not found
if !found {
    set = append(set, element)
}

Removing an Element from the Set

To remove an element from a set implemented as a map, simply delete the key.

1
delete(set, "apple")

When using a slice, you can remove an element like this:

1
2
3
4
5
6
7
element := "apple"
for i, item := range set {
    if item == element {
        set = append(set[:i], set[i+1:]...)
        break
    }
}

Iterating Over a Set

Iterating over a set is straightforward. You can range over the map keys or use a for loop for a slice.

Set Operations

You can perform common set operations like union, intersection, and difference using Go’s set implementations. These operations can be particularly useful in solving more complex problems.

Comparisons with Other Data Structures

It’s essential to understand when to use sets over other data structures. Here’s a brief comparison:

  • Arrays and slices: Sets are ideal when you need to ensure uniqueness and require fast membership testing. Arrays and slices allow duplicates and have O(n) lookup times.

  • Maps: Maps are efficient for key-value pairs but might be overkill when you only need to store unique items.

Performance and Efficiency

Sets in Go are efficient for many use cases. The time complexity for common operations is O(1) due to the use of maps or slices. However, it’s crucial to choose the right implementation based on your specific requirements to optimize memory usage and processing efficiency.

Conclusion

In this blog post, we’ve explored the concept of set data structures in the Go programming language. We’ve discussed their characteristics, implementation, use cases, advantages, and how to work with them in Go applications. Sets are a valuable tool for ensuring uniqueness and improving code efficiency. Whether you use maps or slices, Go provides flexible options to work with sets efficiently.

To further your understanding of sets in Go, I encourage you to explore Go’s documentation and experiment with code examples. Sets can greatly enhance the functionality and performance of your Go applications.

Happy coding with sets in Go! 🚀


We hope you like this post. If you have any questions or suggestions or need any other additional info, please comment below.

We have started a coding community for most frequently used real world coding tips. You can join us here
TipSeason Discord channel
TipSeason Facebook Group

Free AI Prompts + Tools every week

* indicates required
As a bonus, here is an amazing list of prompts for midjourney

What do you want to learn next ? Drop a comment below!