Go Skills

Golang Coding Questions

Coding Questions

1. Print Even-Odd numbers using goroutine and channel

Solution 1 : Simplest way

package main

import (
	"fmt"
	"sync"
)

func main() {

	wg := sync.WaitGroup{}
	numCh := make(chan int)

	wg.Add(1)
	go evenOdd(numCh, &wg)

	for i := 1; i <= 100; i++ {
		numCh <- i
	}
	close(numCh)
	wg.Wait()

}

func evenOdd(numCh chan int, wg *sync.WaitGroup) {
	defer wg.Done()

	for num := range numCh {
		if num%2 == 0 {
			fmt.Println("Even:", num)
		} else {
			fmt.Println("Odd:", num)
		}
	}
}

Solution 2 : Better way

package main

import (
	"fmt"
	"sync"
)

func isEvenOrOdd(num int, result chan<- string, wg *sync.WaitGroup) {
	defer wg.Done()

	if num%2 == 0 {
		result <- fmt.Sprintf("%d is even", num)
	} else {
		result <- fmt.Sprintf("%d is odd", num)
	}
}

func printResults(results <-chan string, done chan<- struct{}) {
	for r := range results {
		fmt.Println(r)
	}
	done <- struct{}{}
}

func main() {
	nums := []int{1, 2, 3, 4, 5}

	var wg sync.WaitGroup

	wg.Add(len(nums))

	results := make(chan string)

	done := make(chan struct{})

	go printResults(results, done)

	for _, num := range nums {
		go isEvenOrOdd(num, results, &wg)
	}

	wg.Wait()
	close(results)

	<-done
}

2. Print Even-Odd numbers using goroutine and channel but in Sequential order

package main

import (
	"fmt"
	"sync"
)

func main() {
	notify := make(chan struct{})
	var wg sync.WaitGroup

	wg.Add(2)
	go even(notify, &wg)
	go odd(notify, &wg)
	notify <- struct{}{}
	wg.Wait()
}

func even(noty chan struct{}, wg *sync.WaitGroup) {
	defer wg.Done()
	for i := 2; i <= 10; {
		<-noty
		fmt.Println("even: ", i)
		if i == 10 {
			close(noty)
			return
		}
		i = i + 2
		noty <- struct{}{}
	}
	return
}

func odd(noty chan struct{}, wg *sync.WaitGroup) {
	defer wg.Done()
	for i := 1; i <= 10; {
		_, ok := <-noty
		if !ok {
			return
		}
		fmt.Println("odd: ", i)
		i = i + 2
		noty <- struct{}{}
	}
	return
}

3. Can you write a program, structure 2 goroutine, each go routine should increment value simultaneously

package main

import (
	"fmt"
	"sync"
)

func main() {
	var wg sync.WaitGroup

	var counter int
	wg.Add(2)

	go func() {
		defer wg.Done()
		for i := 0; i < 1000; i++ {
			counter++
		}
	}()

	go func() {
		defer wg.Done()
		for i := 0; i < 1000; i++ {
			counter++
		}
	}()

	wg.Wait()
	fmt.Println(counter)
}

4. Can you write a program for Last-In-First-Out? (for stack = push, pop)

package main

import "fmt"

type Stack struct {
	items []int
}

func (s *Stack) Push(item int) {
	s.items = append(s.items, item)
}

func (s *Stack) Pop() int {
	if len(s.items) == 0 {
		panic("Stack is empty")
	}
	item := s.items[len(s.items)-1]
	s.items = s.items[:len(s.items)-1]
	return item
}

func (s *Stack) IsEmpty() bool {
	return len(s.items) == 0
}

func main() {
	stack := Stack{}
	stack.Push(1)
	stack.Push(2)
	stack.Push(3)

	for !stack.IsEmpty() {
		fmt.Println(stack.Pop())
	}

}

5. Can you write a program Queue FIFO

package main

import "fmt"

type Queue struct {
	items []int
}

// The Enqueue method adds a new item to the end of the slice using the append built-in function.
func (q *Queue) Enqueue(item int) {
	q.items = append(q.items, item)
}

// The Dequeue method removes and returns the first item in the slice using slicing operations.
// If the slice is empty, the method panics.
func (q *Queue) Dequeue() int {
	if len(q.items) == 0 {
		panic("Queue is empty")
	}
	item := q.items[0]
	q.items = q.items[1:]
	return item
}

// The IsEmpty method returns a boolean indicating whether the slice is empty.
func (q *Queue) IsEmpty() bool {
	return len(q.items) == 0
}

func main() {
	queue := Queue{}
	queue.Enqueue(1)
	queue.Enqueue(2)
	queue.Enqueue(3)

	for !queue.IsEmpty() {
		fmt.Println(queue.Dequeue())
	}
}

6. Implement Binary search tree in golang

package main

import "fmt"

type Node struct {
	data  int
	left  *Node
	right *Node
}

func insert(root *Node, data int) *Node {
	if root == nil {
		return &Node{data, nil, nil}
	} else if data < root.data {
		root.left = insert(root.left, data)
	} else {
		root.right = insert(root.right, data)
	}
	return root
}

func traverseInOrder(root *Node) {
	if root != nil {
		traverseInOrder(root.left)
		fmt.Printf("%d ", root.data)
		traverseInOrder(root.right)
	}
}

func search(node *Node, value int) *Node {
	if node == nil || node.data == value {
		return node
	}

	if value < node.data {
		return search(node.left, value)
	}

	return search(node.right, value)
}

func main() {
	var root *Node
	root = insert(root, 8)
	insert(root, 3)
	insert(root, 10)
	insert(root, 1)
	insert(root, 6)
	insert(root, 14)
	insert(root, 4)
	insert(root, 7)
	insert(root, 13)
	fmt.Printf("In-order traversal of binary tree: ")
	traverseInOrder(root)
	fmt.Println("Searching")
}

8. Can you write a program for a Shoe Factory for Adidas and Nike with help of an interface IShoe having a method. In a way that shoe factory will return instance of desired shoe brand?

Here is an example of how you might implement a shoe factory using an interface in Go:

package main

import "fmt"

type IShoe interface {
	GetBrand() string
}

type Adidas struct{}

func (a *Adidas) GetBrand() string {
	return "Adidas"
}

type Nike struct{}

func (n *Nike) GetBrand() string {
	return "Nike"
}

type ShoeFactory struct{}

func (sf *ShoeFactory) GetShoe(brand string) IShoe {
	if brand == "Adidas" {
		return &Adidas{}
	} else if brand == "Nike" {
		return &Nike{}
	}

	return nil
}

func main() {
	factory := ShoeFactory{}

	adidasShoe := factory.GetShoe("Adidas")
	fmt.Println("Brand:", adidasShoe.GetBrand())  // Output: "Brand: Adidas"

	nikeShoe := factory.GetShoe("Nike")
	fmt.Println("Brand:", nikeShoe.GetBrand())  // Output: "Brand: Nike"
}

In this example, the IShoe interface defines a single method, GetBrand, which returns the brand of the shoe. The Adidas and Nike structs both implement this method to return the appropriate brand name.

The ShoeFactory struct has a method, GetShoe, which takes a brand name as an argument and returns an instance of the appropriate type of shoe. If the brand name is “Adidas”, it returns an instance of the Adidas struct, and if the brand name is “Nike”, it returns an instance of the Nike struct. If the brand name is not recognized, it returns nil.

In the main function, we create an instance of the ShoeFactory and use it to get instances of both an “Adidas” shoe and a “Nike” shoe. We then call the GetBrand method on each of these instances to print the brand name.

9. Notify the other goroutines that his task is completed , the other goroutine should stop execution as got the notification.

10. Design an API to print the list of users along with their posts

package main

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
)

/*
Design an API to print the list of users along with their posts
API response Format: {UserName : "" , Posts[] }

// https://jsonplaceholder.typicode.com/posts
// https://jsonplaceholder.typicode.com/users
*/

type Post struct {
	UserId int    `json:"userId"`
	ID     int    `json:"id"`
	Title  string `json:"title"`
	Body   string `json:"body"`
}

type User struct {
	ID       int    `json:"id"`
	Name     string `json:"name"`
	Username string `json:"username"`
	Email    string `json:"email"`
}

type UserWithPosts struct {
	UserName string `json:"UserName"`
	Posts    []Post `json:"Posts"`
}

func main() {
	port := ":8080"

	http.HandleFunc("/users", getUsersWithPosts)
	log.Println("listening on port", port)
	log.Fatal(http.ListenAndServe(port, nil))

}

func getUsersWithPosts(w http.ResponseWriter, r *http.Request) {
	// Fetch user details
	var users []User

	usersURL := "https://jsonplaceholder.typicode.com/users"

	resp, err := http.Get(usersURL)
	if err != nil {
		http.Error(w, "Failed to fetch user details", http.StatusInternalServerError)
		return
	}
	defer resp.Body.Close()

	// Read the response body
	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		http.Error(w, "Failed to read response body", http.StatusInternalServerError)
		return
	}

	err = json.Unmarshal(body, &users)
	if err != nil {
		http.Error(w, "Failed to unmarshal user details", http.StatusInternalServerError)
		return
	}

	// Fetch posts for each user
	var usersWithPosts []UserWithPosts

	for _, user := range users {
		postsURL := fmt.Sprintf("https://jsonplaceholder.typicode.com/posts?userId=%d", user.ID)

		resp, err := http.Get(postsURL)
		if err != nil {
			http.Error(w, fmt.Sprintf("Failed to fetch posts for user %s", user.Username), http.StatusInternalServerError)
			return
		}
		defer resp.Body.Close()

		postsData, err := ioutil.ReadAll(resp.Body)
		if err != nil {
			http.Error(w, fmt.Sprintf("Failed to read posts response for user %s", user.Username), http.StatusInternalServerError)
			return
		}

		var posts []Post
		err = json.Unmarshal(postsData, &posts)
		if err != nil {
			http.Error(w, fmt.Sprintf("Failed to unmarshal posts data for user %s", user.Username), http.StatusInternalServerError)
			return
		}

		userWithPosts := UserWithPosts{
			UserName: user.Username,
			Posts:    posts,
		}

		usersWithPosts = append(usersWithPosts, userWithPosts)
	}

	// Marshal the response into JSON
	response, err := json.Marshal(usersWithPosts)
	if err != nil {
		http.Error(w, "Failed to marshal response", http.StatusInternalServerError)
		return
	}

	// Set the Content-Type header to application/json
	w.Header().Set("Content-Type", "application/json")

	// Write the response back to the client
	w.Write(response)
}

try yourself mail me solution at amol.asg@gmail.com