golang

Slicing Filters in Golang (Filter Slice)

Slices are a fundamental data structure in Go as they allow us to work with collection of elements.

One of the most common tasks when working with slices is slice filtering.

Slicing filters is an essential technique for working with data collections such as arrays or slices. It allows us to extract specific elements from a slice based on certain criteria.

In this tutorial, we will walk you through the methods that you can use to accomplish this task.

Golang Slices

Before we dive into the process of removing duplicates from a slice, let us explore the basics of slices in case you are not familiar.

What Is a Slice?

In Go, a slice is a dynamically-sized, flexible view into an underlying array. It is a more versatile alternative to arrays as it can grow or shrink as needed without requiring us to specify a fixed size.

We can use slices to represent the sequences of data such as lists, collections, or arrays with dynamic sizes.

A slice is comprised of three main components in Go:

  1. Pointer to the underlying array
  2. Length (number of elements in the slice)
  3. Capacity (maximum number of elements that the slice can hold without resizing the underlying array)

The following shows the basic syntax of declaring a slice in Go:

var slice_name []type

 

Basics of Slices in Go

The first and most common method of creating a slice in Go is using the literal definition as shown in the following example:

databases := []string{"MySQL", "PostgreSQL", "Redis"}

 

We can also use the β€œmake” function to declare a new slice as demonstrated in the following example:

databases := make([]string, 3, 5)

 

This should create a slice of integers with the length of 3 and a capacity of 5.

We can also create a slice by slicing an existing array as follows:

arr := [5]int{1, 2, 3, 4, 5}
slice := arr[1:4]

 

This should create a new slice from the second and fourth elements of the array.

Adding Elements to Slice

In Go, we can add elements to an existing slice using the append() function as shown in the following example:

databases := []string{"MySQL", "PostgreSQL"}
databases = append(databases, "Redis")

 

In the β€œappend” function, we need to pass the existing slice and the new elements that we wish to add to the slice.

Accessing the Elements

We can access the slice elements using the elements index as shown in the following example:

i := databases[0]

 

This should return the first element in the slice.

Iterating Over Slice

We can use a basic β€œfor” loop to iterate over the elements of a slice as shown in the following example:

for i, db := range databases {
    fmt.Printf("Index: %d, Value: %s\n", i, db)
}

 

Golang Filter Slice

Slice filtering involves selecting specific elements that match a specific condition and discarding the ones that do not.

1.Β Β Β Β Β  Using the β€œFor” Loop

This is a basic and common method in data manipulation as shown in the following code example:

package main
import (
    "fmt"
)
func main() {
    nums := []int{1012, 32, 32, 232, 212, 45, 2, 12, 64, 23, 54, 76, 872}
    filtered := []int{}
    for _, num := range nums {
        if num%2 == 0 {
            filtered = append(filtered, num)
        }
    }
    fmt.Println(filtered)
}

 

This uses a based β€œfor” loop and condition checker to remove any elements that are not even numbers.

2.Β Β Β Β Β  Using the Filter Package

For more advanced filtering operations, we can use the external packages like β€œgo-funk”:

https://github.com/thoas/go-funk

This library provides helpers (map, find, contains, filter, and more).

package main
import (
    "fmt"

    "github.com/thoas/go-funk"
)
func main() {
    r := funk.Filter([]int{1, 10, 2, 8, 3, 7, 4, 6, 5, 9}, func(x int) bool {
        return x%2 == 0
    })
    fmt.Println(r)
}

 

This uses the funk package to perform a filter and sort on the slice values.

3.Β Β Β Β Β  Using Channels and Goroutines

For larger slices or complex filter conditions, we can use the goroutines and channels for concurrent filtering.

package main

import (
    "fmt"
)

func concurrentFilter(slice []int, condition func(int) bool) []int {
    result := make([]int, 0)
    ch := make(chan int)

    for _, v := range slice {
        go func(val int) {
            if condition(val) {
                ch <- val
            } else {
                ch <- -1
            }
        }(v)
    }

    for range slice {
        val := <-ch
        if val != -1 {
            result = append(result, val)
        }
    }

    return result
}

func main() {
    numbers := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}

    filtered := concurrentFilter(numbers, func(n int) bool { return n%2 == 0 })

    fmt.Println(filtered)
}

 

This combines the power of goroutines and channels to provide a more complex and concurrent filtering.

Conclusion

In this tutorial, we covered the methods and techniques of performing the slice filtering from the basic β€œfor” loop to the advanced filtering using channels and goroutines.

About the author

John Otieno

My name is John and am a fellow geek like you. I am passionate about all things computers from Hardware, Operating systems to Programming. My dream is to share my knowledge with the world and help out fellow geeks. Follow my content by subscribing to LinuxHint mailing list