Bits
4 min readOct 26, 2022
Set Implementation Using Reference Type Array

Data structures are nothing but custom/ abstract data types designed to provide an efficient way to access computer memory. Below we have implemented a set-type structure using an array.

Definitions

Array: An array is a collection of items of same data type stored at contiguous memory locations.

Set: A set is a data structure that can store any number of unique values in any order.

Slice: A slice is a reference to a contiguous segment of an array

Sets are different from arrays in the sense that they only allow non-repeated, unique values within them.

Objective

We are going to implement a set type. Set as defined above contains unique and non-repeated values. In comparison to an array, the set that we are going to implement can hold multiple data types in a single object. Thus, making it a heterogenous collection of elements.

We are going to implement using generic datatype i.e. interface in go. Generics have been introduced recently and the implementation in go is quite different as compared to other languages. Let's dive into coding without further delay…

Type Definition

Let's define a new type naming it ‘set’. This type will hold the data of any type within any type of slice.

type set[T any] []T

Methods

type SetServicer interface {
Add(ele any)
Remove(ele any)
Length() int
IsEmpty() bool
Contains(ele any) bool
IndexOf(ele any) int
Print()
}

Since we have defined a new local type; access to this type has been restricted. To make it accessible across programs and make its usage flexible, we need to have exposed methods to access this type.

Following the above methods, we have implemented below:-

Add Method

  • To add an element to the set.
// Add: It adds an element of type any within the set.
func (s *set[T]) Add(ele T) {
for _, val := range *s {
if reflect.ValueOf(val) == reflect.ValueOf(ele) {
return
}
}
*s = append(*s, ele)
}

Remove Method

  • To remove an element from the set.
// Remove: It removes an element of type any within the set.
func (s *set[T]) Remove(ele T) {
temp := []T{}
for _, val := range *s {
if reflect.ValueOf(val) != reflect.ValueOf(ele) {
temp = append(temp, val)
}
}
*s = temp
}

Length Method

To get the total length (number of elements) of the set.

// Length: This computes the total length of array. Returns the integer value.
func (s *set[T]) Length() int {
return len(*s)
}

IsEmpty Method

  • Returns true if the set is empty; otherwise returns false.
// IsEmpty: Returns true if length is grether than 0.
func (s *set[T]) IsEmpty() bool {
if len(*s) > 0 {
return false
} else {
return true
}
}

Contains Method

  • Checks whether an element is present in the set.
  • If present returns true else returns false.
// Contains: Returns true if an element is present in the set.
func (s *set[T]) Contains(ele T) bool {
for _, val := range *s {
if reflect.ValueOf(val) == reflect.ValueOf(ele) {
return true
}
}
return false
}

IndexOf Method

  • If the element is present in the set; it returns the index of the element
  • If the element is not present in the set; it returns -1.
// IndexOf: Returns the index of the element in the set.
func (s *set[T]) IndexOf(ele T) int {
for key, val := range *s {
if reflect.ValueOf(val) == reflect.ValueOf(ele) {
return key
}
}
return -1
}

Print Method

  • Responsible to print all the elements of the set.
// Print: Responsible to print all the elements of the set.
func (s *set[T]) Print() {
fmt.Println(*s)
}

Constructor

A constructor is a special function that initializes a newly created object of particular type.

Finally, we need a constructor to assign memory to our set type object.

func NewSet() SetServicer {
var s set[any]
return &s
}

Main

Below we can verify our set type and its custom methods.

func SetTest() {
s := NewSet()
s.Add(4)
s.Add(4)
s.Add(5)
s.Add(6)
s.Add(7)
s.Add(8)
s.Add(8)
fmt.Println("Length : ", s.Length())
s.Print()
s.Remove(4)
fmt.Println("Length : ", s.Length())
s.Print()
s.Remove(5)
fmt.Println("Length : ", s.Length())
s.Print()
fmt.Println("Contains 7: ", s.Contains(7))
fmt.Println("Index of 7: ", s.IndexOf(7))
}
/* Output
Length : 5
[4 5 6 7 8]
Length : 4
[5 6 7 8]
Length : 3
[6 7 8]
Contains 7: true
Index of 7: 1
*/

We can also add different types of elements within the same set.

func SetTest() {
t := NewSet()
t.Add("abc")
t.Add("def")
t.Add("ghi")
t.Add(123)
fmt.Println("Length : ", t.Length())
t.Print()
t.Remove("abc")
fmt.Println("Length : ", t.Length())
t.Print()
fmt.Println("Contains def: ", t.Contains("def"))
fmt.Println("Index of def: ", t.IndexOf("def"))
}
/* Output
Length : 4
[abc def ghi 123]
Length : 3
[def ghi 123]
Contains def: true
Index of def: 0
*/

This way we have set as our custom type and standard methods to manipulate our custom-type object.

Set Implementation Using Reference Type Array

Hope this article helps to get a basic understanding of custom types and program structure. Please comment below in case of any errors or further suggestions. Thanks!