Javascript: How to Sort a regular object based on key and value

Javascript: How to Sort a regular object based on key and value

Assume like you have an object { '1': 1, '3': 1, '4': 3, '5': 1 } and you would like to sort it by its value.

Then you can follow below way. I just added debug information to help with visulization but the function you need is simply

Sort by value

Object.entries(obj).sort(function(a, b) { return a[1] - b[1] }); 

And if you would like to sort by key then

Object.entries(obj).sort(function(a, b) { return a[0] - b[0] }); 

Debug Code

> Object.entries(obj)                                                                                                                                                                                       
[ [ '1', 1 ], [ '3', 1 ], [ '4', 3 ], [ '5', 1 ] ]                                                                                                                                                          
> Object.entries(obj)[0]                                                                                                                                                                                    
[ '1', 1 ]                                                                                                                                                                                                  
> Object.entries(obj)[0][0]                                                                                                                                                                                 
'1'                                                                                                                                                                                                         
> Object.entries(obj).sort(function(a, b) { return a[1] - b[1] });                                                                                                                                          
[ [ '1', 1 ], [ '3', 1 ], [ '5', 1 ], [ '4', 3 ] ]                                                                                                                                                          
> obj                                                                                                                                                                                                       
{ '1': 1, '3': 1, '4': 3, '5': 1 }                                                                                                                                                                          
> 
> Object.entries(obj).sort(function(a, b) { return a[0] - b[0] });                                                                                                                                          
[ [ '1', 1 ], [ '3', 1 ], [ '4', 3 ], [ '5', 1 ] ]                                                                                                                                                          
> 

Hope it helps.

Notes: GoLang - Types & Methods - Part I

Notes: GoLang - Types & Methods - Part I
  • Go is a statically typed language with both built in types and user defined types.
  • Abstraction methods allowed in go, which allowing you to write code that invokes methods without inplementation.

Types in Go

  • Like we define structs, we can also define any other type in go, for example all below declarations are valid in go
type Student struct {
	rollno int
	name string
	marks int
}

type AvgMarks float
type Section string
type Avg func(int)AvgMarks
type ClassAvgMarks func(int, int)AvgMarks

  • Types like these can be declared at level with no restrictions but type can be accessed within its scope unless they are expored package block level types.

Abstract Types is one that specifies what a type should do, but not how it is done.

Concrete Type specifies what and how, like implementation of the method.

Methods

  • On userdefined types like above, methods can be declared.
  • If we define any methods on specified types, then they will have a receiver specification between the keyword func and the name of the method.
  • And here the receiver will have a short name similar to this or self
  • No method overloading
  • We can use same method name for different types.
  • Methods must be on the same package level where the respective type has been creted.

Pointer Receivers and Value Receivers

  • Go uses parameter of pointer type to indicate that a parameter might be modified by the function.
  • Method receivers has same principle
    • pointer receivers : type is a pointer
      • If any method modifies the receiver, you must use a pointer receiver
      • if your method needs to handle nil instances , then a pointer receiver
    • value receivers: type is a value
      • If your method doesnt modify the receiver, you can use a value receiver.

package main

import (
	"fmt"
	"time"
)

type Counter struct {
	total       int
	lastUpdated time.Time
}

func (c *Counter) Increment() {
	c.total++
	c.lastUpdated = time.Now()
}

func (c Counter) String() string {
	return fmt.Sprintf("Total %d , lastUpdatedOn %v", c.total, c.lastUpdated)
}

func main() {
	var c Counter
	fmt.Println(c)
	c.Increment()
	fmt.Println(c.String())
	c.Increment()
	fmt.Println(c.String())

}

// Output
/*
Total 0 , lastUpdatedOn 0001-01-01 00:00:00 +0000 UTC
Total 1 , lastUpdatedOn 2009-11-10 23:00:00 +0000 UTC m=+0.000000001
Total 2 , lastUpdatedOn 2009-11-10 23:00:00 +0000 UTC m=+0.000000001

Program exited.
*/

  • Similarly, if you pass this type as value to other functions as an argument, then you are not sending its reference, you are making a copy of it and sending, so any changes are limited to that method only. For example

package main

import (
	"fmt"
	"time"
)

type Counter struct {
	total        int
	lastUpdateOn time.Time
}

func (c *Counter) Increment() {
	c.total++
	c.lastUpdateOn = time.Now()
}

func (c Counter) String() string {
	return fmt.Sprintf("Counter %d , updated On %v", c.total, c.lastUpdateOn)
}

func passByValueChangesLimitToThisFunction(c Counter) {
	c.total++
	c.lastUpdateOn = time.Now()
	fmt.Println("Pass by valuce, changes limited to end of this function", c.String())
}

func passByReferenceChangesAppliedToInstance(c *Counter) {
	c.total++
	c.lastUpdateOn = time.Now()
	fmt.Println("Pass by reference, changes applies to struct instance", c.String())
}

func main() {
	var c Counter
	fmt.Println(c.String())

	passByValueChangesLimitToThisFunction(c)
	fmt.Println("After calling pass by value mode, still values stays same", c.String())

	passByReferenceChangesAppliedToInstance(&c)
	fmt.Println("After calling pass by ref mode, changes applied to instance ", c.String())
}
  • Dont write explicit method to fetch/get data from struct instances, unless you need them explicitly.

Notes: GoLang - Maps vs Slices and Using Slice as buffer

Notes: GoLang - Maps vs Slices and Using Slice as buffer

Maps vs Slices

  • In go maps are refernce oriented. If you pass a map to a function as argument, any changes to that map inside the function will reflect to original function as well.
package main

import (
	"fmt"
)

func main() {
	var testMap = make(map[string]string)
	testMap["lang"] = "go"
	fmt.Println("Before updating the map")
	fmt.Println("-------------")
	for key, val := range testMap {
		fmt.Println(key, val)
	}

	_ = updateMap(testMap)
	fmt.Println()
	fmt.Println("Before updating the map in another function")
	fmt.Println("-------------")
	for key, val := range testMap {
		fmt.Println(key, val)
	}
}

func updateMap(testMap map[string]string) map[string]string {
	testMap["type"] = "compiled"
	return testMap
}

  • The main reason behind this is, in Go maps are implemented as pointer to structs
  • In the runtime Go implements a struct based on the map.
    Ref: https://dave.cheney.net/2018/05/29/how-the-go-runtime-implements-maps-efficiently-without-generics
  • Passing a map to function means that you are copying a pointer i.e address/reference of the map, so any changes to map will happen at the memory of the map.
  • While designing APIs, having maps as input or return values is bad choice due to we dont what that map contained.
  • As you pass the map and these are something similar to updated by reference, in any where of your code, if you update the map, there is no of knowing unless we inspect the code.
  • So during the cases where map implementation needed, we can leverage struct, as to struct update will not have any thing like reference, so you must return the struct to know the changes
package main

import (
	"fmt"
)

type Student struct {
	name string
	num  int
}

func main() {

	s := Student{"student1", 111}
	fmt.Println(s.name)
	newName := "student2"
	
	// case 1 not caputering it
	_ = updateStudentName(newName, s)
	fmt.Println(s.name)
	
	// case 2 caputering it
	s = updateStudentName("Student3", s)
	fmt.Println(s.name)

}

func updateStudentName(newName string, s Student) Student {
	s.name = newName
	return s
}
  • When it come to slices, they are updated by reference at one case and they are not yet another.
  • To put it in simple words, under criteria of length and capacity, if you update a slice and its copy as long as it maintaines the same memory location pointer, both will get updated.
  • but if some append operation which might change length of slice, then Go runtime will try to use existing slice capacity else create a new memory location and thats where the break will happen with orignial slice and new slice in terms of memory location.
  • if go trying to use existing slice reserved capacity, then it will be a shared scenario. Slice1 and Slice2 will share what ever the data common and new data appended to slice2 will be hidden from slice1, and length of slice1 also will not change.
package main

import (
	"fmt"
)

func main() {

	slice1 := make([]int, 5, 5)
	slice1 = []int{1, 2, 3, 4, 5}
	fmt.Println(slice1)

	slice2 := slice1
	fmt.Println(slice2)

	// update by changing existing
	slice2[0] = 100
	fmt.Println(slice1)
	fmt.Println(slice2)

	// now do append
	slice2 = append(slice2, 101)
	fmt.Println(slice2)
	fmt.Println(slice1)
}

Slices As Buffers

  • So as long as you replace data to slice, it size and length wont get change.
  • so the memory location wont change
  • every time old data processing completed, new data get placed into the same memory location.
  • so garbage collection is only once and that is the end of the complete Read operation.
  • to read from file, we create the famous byte buffer and every time read the chunk of byte from the sources
  • then process it
data := make([]byte, 100)
count, err := file.Read(data)
// count is length of chunk that we read
// err returns if any 

Notes: GoLang

Notes: GoLang

GoLang Notes

Outline

Iterate Over String

Switch Case

Execute Shell Commands

Iterate_Over_String

var name string;
name = "GoLang";
for index, value := range name {
  fmt.Printf("Index %d Char %c\n", index, value);
  }

Switch-Case

for _, value := range "Golang" {
  switch value {
    case 'G' : fmt.Println("Case G executed")
    case 'l' : fmt.Println("Case I executed")
   }
  }

Execute-Shell-Commands

Ref: https://pkg.go.dev/os/exec@go1.17.6

package main

import (
  "fmt"
  "os/exec"
)

func main() {

  command := "uptime"
  output, error := exec.Command(command).Output()
  if error != nil {
    fmt.Println("Received error while executing the command")
  } else {
    fmt.Printf("Command %s output %s ", command, output)
  }
}

Output

❯❯ sysadmin_programming_tasks git:(my-code-go) 12:02 go run execute_uptime_command_1.go
Command uptime output  12:02:42 up  1:29,  1 user,  load average: 0.34, 0.44, 0.63

Go Routines and Concurrency

[Refernces]

Notes

  • to use go routines just use the place go before the code.
  • for example if you want to execute function like count("Sheep") in async using go routines then you modify the line as
go count("sheep")
  • so what will happen is that go will start executing this in the background and move to next line.
  • dont add your go routine as last line of your main method. As per go programming if go ccoroutine reaches to last line then program will exit.
  • to avoid that you can use a trick placing fmt.Scanln() and that make the main program wais for user to enter the input.
  • But to do this properly we can leverage sync pacakge Waitgroup interface
package main

import (
	"fmt"
	"time"
	"sync"
)

func main() {
	var wg sync.WaitGroup
	wg.Add(1)

	go func() {
		count("sheep")
		wg.Done()
	}() // anonymous function.
}

func count(thing string) {
	for i := 1; i <= 5; i++ {
		fmt.Println(i, thing)
		time.Sleep(time.Millisecond * 500)
	}
}

Channel

  • channels are for go routines to communicate with each other.
  • we can channel a type and send messages through that channel
  • we can send a channel through a channel
  • define channel with chan
  • channel kind of block the communication, if channel is sending a message then it will wait till the message received.
  • and if a channel is supposed to receieve a message, then it will wait till that message is received.
  • to send a channel c <- thing
  • to receive from a channel thing := <- c
  • the syncronize go routines we use channels, because they block execution by waiting for to receive the data/response.
  • A channel received can send/ receive at only one time. To receive perform this receive/sending multiple times we have iterate over the data.
  • As a sender you know how much data you have to send, but as a receiver you dont know how much data you should receive, so always be in a state of waiting for the data if your channel is waiting for the data.
  • As a sender, you can close the channel using close() function by passing channel as argument and that will close the channel at the receiver end as well.
  • at the receiver end, we get a bool true if channel is opened, so we can monitor that to know whether channel opened or not at the receiver end.
package main

import (
	"fmt"
	"time"
)

func main() {
	c := make(chan string) // creating a string type channel
	go count("sheep", c) // passing channel as argument to function 
	for msg := range c { // instead of checking on bool like msg, open we are checking for data thats coming out of the channel 
		fmt.Println(msg)
	}
}

func count(thing string, c chan string) {
	for i := 1; i <= 5; i++ {
		c <- thing
		time.Sleep(time.Millisecond * 500 )
	}

	close(c)
}

Channel Blocking

  • if you are trying to sending data via channel, as you are sender, there must be a receiver created already, for example
package main

import (
	"fmt"
)

func main() {
	c := make(chan string)
	c <- "hello" // you are sending data to channel, but receiver not created yet, so your program blocked here, as this line exxecuted its trying to send the data but no receiver is ready to receive the data. 

	msg := <- c
	fmt.Println(msg)

}
  • so resolve issues like this, we can define size of the channel like block, and channel will take those many block and hold it and lets compiler to move forward, in simple words it wont block the execution as long as up to reserved block data given, for example
package main

import (
	"fmt"
)

func main() {
	c := main(chan string, 2) // 2 bugger block
	c <- "Hello" // block 1
	c <- "World" // block 2

	msg := <- c
	fmt.Println(msg)

	msg := <- c
	fmt.Println(msg)
}
  • Now this code works fine, but if you try to send another buffer block of data via channel like c <- "3rd block" then it wont work, this time as it cant hold it must need a receiver.

Channel Selectors

  • if you are trying to read data from multiple channels like
for {
	fmt.Println(<-c1)
	fmt.Println(<-C2)
}

then what happens here is that, till C2 channel completes its execution (like till it receives the data, it will block the execution of c1 )

package main

import (
	"fmt"
)

func main() {

	// creating two channels
	c1 := make(chan string)
	c2 := make(chan string)

	go func() {
		for {
			c1 <- "Every 500ms"
			time.Sleep(time.Millisecond * 500 )
		}
	} ()

	go func() {
		for {
			c2 <- "Every two seconds"
			time.Sleep(time.Second * 2 )
		}
	} ()

	for {
		fmt.Println(<-c1)
		fmt.Println(<-c2)
	}

}

So to avoid blocking of one channel as its waiting for the response we can use select case statements to read the data from the channel which ever is ready with data received.

package main

import (
	"fmt"
)

func main() {

	// creating two channels
	c1 := make(chan string)
	c2 := make(chan string)

	go func() {
		for {
			c1 <- "Every 500ms"
			time.Sleep(time.Millisecond * 500 )
		}
	} ()

	go func() {
		for {
			c2 <- "Every two seconds"
			time.Sleep(time.Second * 2 )
		}
	} ()

	for {
		select {
		case msg1 := <- c1 :
			fmt.Println(msg1)
		case msg2 := <- c2 :
			fmt.Println(msg2)
		}
	}
}

Workerpool Pattern

By using workpool patterns we can trigger multiple go routines without blocking any channel or thread. Need to dig into this concept more like what are the use cases, below code fibnoci calculation for 100 numbers


package main

import (
	"fmt"
)

func main() {
	jobs := make(chan int, 100)
	results := make(chan int, 100)

	go worker(jobs, results)
	go worker(jobs, results)
	go worker(jobs, results)
	go worker(jobs, results)

	for i := 0; i < 100; i++ {
		jobs <- i
	}
	close(jobs)

	for j := 0; j < 100; j++ {
		fmt.Println(<-results)
	}
}

func worker(jobs <-chan int, results chan<- int) {
	for n := range jobs {
		results <- fib(n)
	}
}

func fib(n int) int {
	if n <= 1 {
		return n
	}

	return fib(n-1) + fib(n-2)
}

If you want to execute a function only for a specific period of time, go go-routines with channel is a great combination. All you have to do is trigger another go routine which do the sleep functionality and then close the channel on which the communication right now happening.


    package main

    import (
        "fmt"
        "time"
    )

    func main() {
        c := make(chan string) // creating a string type channel
        go count("sheep", c)   // passing channel as argument to function
        go sleep(c)
        for msg := range c { // instead of checking on bool like msg, open we are checking for data thats coming out of the channel
            fmt.Println(msg)
        }
    }

    func sleep(c chan string) {
        time.Sleep(time.Second * 5)
        fmt.Println("in sleep method")
        close(c)
        fmt.Println("in sleep method")
    }

    func count(thing string, c chan string) {
        for i := 1; i <= 5; i++ {
            c <- thing
            time.Sleep(time.Millisecond * 500)
        }

    }

Few Tips To Overcome Unstable Mind

Few Tips To Overcome Unstable Mind

The silly truth I realized, when you have fears, and if your mind becomes unstable, then events happening in your day might take over you and your day and that will lead to procrastination, the feeling of dont want to do anything.

In some other words, we might also call it as depression and if you also feel that the task at your hand is either completely new to you or you dont like at all.

But if you like the task at your hand then all these fears, events that might unstable you will not have any impact.

So to make or build the task which you dont like you have to break the task into into known and unknown piece. Then devide your time.

When your mind is stable, focus on unknown things because in tough times to move forward what we need is hope and will power which are like twin sisters, one doesn’t exist without the other.

When your mind is not stable focus on known things which can be completed with no effort, focus on things which you know how to deal. Now this will help to bring back your stability. As the task is not completely new and you know how to do it, you will start doing it. So you are not feeding the unstable thoughts any more and you are becoming focused and aware and your mind starts to become stable.

But sometimes, known tasks which are boring like reviwing other’s work, reading word docs, reading mails might not help. Because I want you to think with visualizations and assumptions.

Here is the key point #1, when your mind is unstable its getting feeded by your assumptions and your visulizations of negative thoughts or events , and now stop feeding your mind with those assumptions and visualizations and feed them something else, like known but interesting tasks at your hand, or close your eyes and go with imagination that you are doing great or you have achieved your long-term goals, so this will give you a great feeling, so close your eyes and feel it.

And one more key point #2, always focus on moving forward, something unexpected happened today with work life or personal life, dont stop there and feel sad about it, its okay take your time to come out but dont stop there, from your schedule / plan (which is very important) and move forward.

And last one, if you have positive energy, spread that around. if you spread positive energy, it will help the people with negtative or depressed state of mind to feel better and to spark a positive light inside their mind. If you have a negative feeling dont spread that around and use the #1 key point from above and turn your self/mind into positive.

You just read 500 + words.
Hope it helps you.


Thank you.
Raaz