# Go - Playing with Records - Part Two

Article Series

Playing with Records Related Articles.

Table of Content
Where to Discuss?

Local Group

### Preface

Goal: Continue Part One

### 4: Approach in Solving Unique

A custom pattern matching example, that you can rewrite.

#### An Algorithm Case

Why making things complex?

My intention is writing a custom pattern matching example, so later I can rewrite other algorithm based on this example. You can read the detail on the first article. The record overview.

Consider going back to simple data. We need to discuss about solving unique list.

#### Head and Tail Pattern Matching

The original `x:xs` pattern matching from `haskell` shown as below:

``````exclude :: String -> ([String] -> [String])
exclude value = filter((/=) value)

unique :: [String] -> [String]
unique [] = []

tags :: [String]
tags = ["rock", "jazz", "rock", "pop", "pop"]

main = print (unique tags)``````

With the result of

``````["rock","jazz","pop"]
``````

This `x:xs` pattern is made of two functions:

1. Exclude
2. Unique

#### Loop for Exclude

Based on

``````exclude :: String -> ([String] -> [String])
exclude value = filter((/=) value``````

We can rewrite twoliners above to this below:

``````package main

import "fmt"

func exclude(value string, tags []string) []string {
var newTags []string

for _, tag := range tags {
if tag != value {
newTags = append(newTags, tag)
}
}

return newTags
}

func main() {
var tags = []string{
"rock", "jazz", "rock", "pop", "pop"}

fmt.Println(exclude("rock", tags))
}``````

With the result similar as below `slices`:

``````\$ go run 08-exclude.go
[jazz pop pop]
``````

#### Loop for Unique

Based on

``````unique :: [String] -> [String]
unique [] = []

We can rewrite threeliners above to this below:

``````package main

import "fmt"

func exclude(value string, tags []string) []string {
â€¦
}

func unique(tags []string) []string {
if len(tags) <= 1 {
return tags
} else {
tail := tags[1:len(tags)]

}
}

func main() {
var tags = []string{
"rock", "jazz", "rock", "pop", "pop"}

fmt.Println(unique(tags))
}``````

With the result similar as below `slices`:

``````\$ go run 09-unique.go
[rock jazz pop]
``````

#### The Recursive

Based on

``â€¦ = head:unique(exclude head tail)``

Transformed into

``````	head := tags[0]
tail := tags[1:len(tags)]

I guess the code itself is self explanatory.

#### myutils Package

The code can be shown as below:

``````package myutils

func exclude(value string, tags []string) []string {
â€¦
}

func Unique(tags []string) []string {
â€¦
}``````

I keep the `exclude` function with lowercase, while changing `unique` function to uppercase.

#### Configuration

The `go.mod` file is simply as below setting

``````module mysongs

go 1.15``````

And the `go.mod` file for root directory has some settings:

``````module tutor

go 1.15

replace example.com/mysongs => ./mysongs
require example.com/mysongs v1.0.0

replace example.com/myutils => ./myutils
require example.com/myutils v1.0.0``````

#### Clean Up

Now we can have a short and tidy code.

``````package main

import (
"example.com/mysongs"
"example.com/myutils"
"fmt"
)

func main() {
var tags []string
tags = mysongs.GetSongs().FlattenTags()
tags = myutils.Unique(tags)
fmt.Println(tags)
}``````

With the result similar as below `slices`:

``````\$ go run 10-cleanup.go
[60s jazz rock 70s pop]
``````

Now you can rewrite your own pattern matching algorithm to `go`.

### 5: Concurrency using Goroutine

Before we make a complex goroutine, we can utilize previous flatten example, as a show case to pass data between `goroutine`.

#### Passing by Reference

To use `defer` with array of string, I need to explain `pointer` a bit.

When we run a goroutine, we need to pass variable as parameter argument in function. In order to change the value of the parameter , we need to pass it by reference.

``````func flatten(songs []mysongs.Song, tags *[]string) {
â€¦
}``````

And change the value later by uisng pointer.

``*tags = append(*tags, tag)``

The complete code is as below:

``````package main

import (
"example.com/mysongs"
"fmt"
)

func flatten(songs []mysongs.Song, tags *[]string) {
for _, song := range songs {
if song.Tags != nil {
for _, tag := range song.Tags {
*tags = append(*tags, tag)
}
}
}
}

func main() {
var tags []string
flatten(mysongs.GetSongs(), &tags)
fmt.Println(tags)
}``````

_.

With the result similar as below `slices`:

``````\$ go run 11-byref.go
[60s jazz 60s rock 70s rock 70s pop]
``````

#### Waitgroup

Following the official documentation, we can apply `waitgroup` for this situation.

Consider start with `defer`.

``````package main

import (
"example.com/mysongs"
"fmt"
"sync"
)

func flatten(wg *sync.WaitGroup,
songs []mysongs.Song, tags *[]string) {
defer wg.Done()

for _, song := range songs {
if song.Tags != nil {
for _, tag := range song.Tags {
*tags = append(*tags, tag)
}
}
}
}``````

And apply the `waitgroup` pattern` in main function:

``````func main() {
wg := &sync.WaitGroup{}
var tags []string

go flatten(wg, mysongs.GetSongs(), &tags)

wg.Wait()
fmt.Println(tags)
}``````

With exactly the same result as previous `slices`:

``````\$ go run 12-defer.go
[60s jazz 60s rock 70s rock 70s pop]
``````

#### Passing Data Between Channel

We need to create two functions. The `flatten` itself, and other function to `walk` the result.

The `flatten` function is very similar as previous code.

``````func flatten(message chan string, quit chan int) {
songs := mysongs.GetSongs()

for _, song := range songs {
if song.Tags != nil {
for _, tag := range song.Tags {
message <- tag
}
}
}

quit <- 0
}``````

_.

On the other hand, the `walk` function is, following the example from official documentation.

``````func walk(message chan string, quit chan int) {
var tags []string
var tag string

for {
select {
case tag = <-message:
tags = append(tags, tag)
case <-quit:
fmt.Println(tags)
return
}
}
}``````

Now we can call both functions, in `main`.

``````package main

import (
"example.com/mysongs"
"fmt"
)

func walk(message chan string, quit chan int) {â€¦}
func flatten(message chan string, quit chan int) {â€¦}

func main() {
message := make(chan string)
quit := make(chan int)

go flatten(message, quit)
walk(message, quit)
}``````

With exactly the same result as previous `slices`:

``````\$ go run 13-channel.go
[60s jazz 60s rock 70s rock 70s pop]
``````

### What is Next ðŸ¤”?

There is however other way to make our life simpler. We can query using `Koazee`, `go-linq` or `go-funk`.

Consider continue reading [ Go - Playing with Records - Part Three ].