Frequency Counter
Tags: javascript, algorithms, programming, tutorial
Published: 2022-04-14 18:44:59

This pattern employs JavaScript Object to store the frequency or rather the occurrence of data and is most useful in data comparison.

Let's jump right in with an example.

Write a function named similar such that it accepts two (2) arrays. The intended function should return true if every value in array one has its corresponding value squared in array two.

such as 

```
similar([1,2,3],[4,1,9])   this would return true
similar([1,2,1],[4,4,1])   this would return false
```

**Making use of the Frequency Counter Approach Below:**

```
function similar(array1, array2) {

    if (array1.length !== array2.length){
        return false;    
    }
    
    let freqCounter1 = {};
    let freqCounter2 = {};

    for(let val of array1){
        freqCounter1[val] = (freqCounter1[val] || 0) +1      
    }

    for(let val of array2){
        freqCounter2[val] = (freqCounter2[val] || 0) +1      
    }

    
    for(let key in freqCounter1){
       
        if(!(key ** 2 in freqCounter2)){
            return false
        }

        if(freqCounter2[key ** 2] !== freqCounter1[key]) {
            return false;
        }
    }
    
   return true; 
}
```
**Test Case**: 

> 
similar([1,2,3,2,5],[4,9,4,1]) returns `false`
similar([1,2,3],[9,1,4]) returns `true`


**Explanation**

So let's take things in a systematic approach. Feel free to employ the intended approach we went through in the last lesson to solve the problem set yourself.


- **Function Declaration:** declaration of a function named `similar` which would take a set of two distinct arrays as an input.




- **Edge Case:** `the first block of code after the function declaration.` This can be referred to as a short circuit whereby it runs before the core algorithms logic and returns a set result in case of invalid or undesired input.

>  In this case, check if the length of the first array is not equal to that of the second array and returns an output. In this case, it just returns a false statement. 




- **Objects declaration:** you can say this is where the core logic of this approach relies on, but note it doesn’t necessarily have to be an object, such that it can also be an array, although the Big O of Object states that we have a constant rate of accessing, removing, and adding an item into it, which makes it a much-optimized choice. 
Empty Objects were declared to store the frequency of each character in the array respectively as named above. 

> 
The same goes for freqCounter2.




- **Core Objective:** now let's focus on the core objective, which is to look for the presence of the square of each character in array1 within array2. From the block of code `for(let key in freqCounter1){` we loop through each key within freqCounter1 in other to make comparisons, such as this resulting block of code  `if(!(key ** 2 in freqCounter2)){` which acts as a short circuit which checks if the square of each key in **freqCounter1** is not present in **freqCounter2**, and return false.


- 
**Final Piece:** Now the final block of code is aimed at checking if the square of each element in **freqCounter2** has a corresponding equal within **freqCounter1**. If any is found wanting 😩, its evaluates to false, and if not we arrive at the end of the code block where our code `retuns true; `if all conditions were passed.


---

> **Another Example**

Given two strings, write a function to determine if the second string is an anagram of the first. an anagram is a word, phrase, or name formed by rearranging the letters of another, such as `RAT is an anagram of TAR`


```
function anagrams(first, second) {

    if(first.length !== second.length){
        return false;
    }


    let freqCounter1 = {};
    let freqCounter2 = {};

    for(let val of first){
        freqCounter1[val] = (freqCounter1[val] || 0) +1
    }

    for(let val of second){
        freqCounter2[val] = (freqCounter2[val] || 0) +1
    }

    console.log(freqCounter1);
    console.log(freqCounter2);

    for(let key in freqCounter1){
        if(!(freqCounter2.hasOwnProperty(key))){
            return false
        }

        if(freqCounter1.values !== freqCounter2.values){
            return false;
        }
    }

    return true;
}
```

**Test Case**: 

> 
similar(bat, tab) returns `true`
similar(salt, tale) returns `false`


**Final Example**
Count unique Integers in a List

```
function countUnique(arr) {

    let counter = {};
    let count = [];
    
    for(let val of arr){

        counter[val] = (counter[val] || 0) +1;     
    }


    for(let key in counter){
        count.push(key)
    }

    return count.length;
}

```

 **countUnique([-2,-1,-3,1])**
returns `4`


I hope the above examples shed light on the conceptualized pattern discussed. See you in the next lecture.