feat: Test running overhaul, switch to Prettier & reformat everything (#1407)

* chore: Switch to Node 20 + Vitest

* chore: migrate to vitest mock functions

* chore: code style (switch to prettier)

* test: re-enable long-running test

Seems the switch to Node 20 and Vitest has vastly improved the code's and / or the test's runtime!

see #1193

* chore: code style

* chore: fix failing tests

* Updated Documentation in README.md

* Update contribution guidelines to state usage of Prettier

* fix: set prettier printWidth back to 80

* chore: apply updated code style automatically

* fix: set prettier line endings to lf again

* chore: apply updated code style automatically

---------

Co-authored-by: github-actions <${GITHUB_ACTOR}@users.noreply.github.com>
Co-authored-by: Lars Müller <34514239+appgurueu@users.noreply.github.com>
This commit is contained in:
Roland Hummel
2023-10-03 23:08:19 +02:00
committed by GitHub
parent 0ca18c2b2c
commit 86d333ee94
392 changed files with 5849 additions and 16622 deletions

View File

@ -15,20 +15,15 @@ jobs:
- uses: actions/setup-node@v3 - uses: actions/setup-node@v3
with: with:
node-version: 16 node-version: 20
cache: npm cache: npm
- name: 📦 Install dependencies - name: 📦 Install dependencies
run: npm ci run: npm ci
- name: 🧪 Run all tests - name: 🧪 Run all tests
if: ${{ github.event_name == 'push' }}
run: npm run test run: npm run test
- name: 🧪 Run tests for changed files only
if: ${{ github.event_name == 'pull_request' }}
run: npm run test-changed
- name: 💄 Code style - name: 💄 Code style
run: npm run style run: npm run style

View File

@ -63,7 +63,7 @@ globby([
"!**/test/**/*", "!**/test/**/*",
'!**/*.test.js', '!**/*.test.js',
'!**/*.manual-test.js', '!**/*.manual-test.js',
'!babel.config.js' '!vitest.config.ts'
]) ])
// create markdown content // create markdown content
.then(pathsToMarkdown) .then(pathsToMarkdown)

View File

@ -11,16 +11,17 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v3
- uses: actions/setup-node@v3 - uses: actions/setup-node@v3
with: with:
node-version: 16 node-version: 20
cache: npm cache: npm
- name: 📦 Install dependencies - name: 📦 Install dependencies
run: npm ci run: npm ci
- name: 🗄️ Create Directory from JS files - name: 🗄️ Create Directory from JS files
run: node .github/workflows/UpdateDirectory.mjs run: node .github/workflows/UpdateDirectory.js
- name: Configure Github Action - name: Configure Github Action
run: | run: |

View File

@ -2,4 +2,4 @@
. "$(dirname "$0")/_/husky.sh" . "$(dirname "$0")/_/husky.sh"
npm run style npm run style
npm run test-changed npm run test

2
.prettierignore Normal file
View File

@ -0,0 +1,2 @@
.github
DIRECTORY.md

View File

@ -22,14 +22,14 @@
*/ */
class Combinations { class Combinations {
constructor (n, k) { constructor(n, k) {
this.n = n this.n = n
this.k = k this.k = k
this.current = [] // will be used for storing current combination this.current = [] // will be used for storing current combination
this.combinations = [] this.combinations = []
} }
findCombinations (high = this.n, total = this.k, low = 1) { findCombinations(high = this.n, total = this.k, low = 1) {
if (total === 0) { if (total === 0) {
this.combinations.push([...this.current]) this.combinations.push([...this.current])
return this.combinations return this.combinations

View File

@ -10,14 +10,14 @@
*/ */
const swap = (arr, i, j) => { const swap = (arr, i, j) => {
const newArray = [...arr]; const newArray = [...arr]
[newArray[i], newArray[j]] = [newArray[j], newArray[i]] // Swapping elements ES6 way ;[newArray[i], newArray[j]] = [newArray[j], newArray[i]] // Swapping elements ES6 way
return newArray return newArray
} }
const permutations = arr => { const permutations = (arr) => {
const P = [] const P = []
const permute = (arr, low, high) => { const permute = (arr, low, high) => {
if (low === high) { if (low === high) {

View File

@ -1,12 +1,12 @@
// Wikipedia: https://en.wikipedia.org/wiki/Knight%27s_tour // Wikipedia: https://en.wikipedia.org/wiki/Knight%27s_tour
class OpenKnightTour { class OpenKnightTour {
constructor (size) { constructor(size) {
this.board = new Array(size).fill(0).map(() => new Array(size).fill(0)) this.board = new Array(size).fill(0).map(() => new Array(size).fill(0))
this.size = size this.size = size
} }
getMoves ([i, j]) { getMoves([i, j]) {
// helper function to get the valid moves of the knight from the current position // helper function to get the valid moves of the knight from the current position
const moves = [ const moves = [
[i + 2, j - 1], [i + 2, j - 1],
@ -19,15 +19,17 @@ class OpenKnightTour {
[i - 1, j + 2] [i - 1, j + 2]
] ]
return moves.filter(([y, x]) => y >= 0 && y < this.size && x >= 0 && x < this.size) return moves.filter(
([y, x]) => y >= 0 && y < this.size && x >= 0 && x < this.size
)
} }
isComplete () { isComplete() {
// helper function to check if the board is complete // helper function to check if the board is complete
return !this.board.map(row => row.includes(0)).includes(true) return !this.board.map((row) => row.includes(0)).includes(true)
} }
solve () { solve() {
// function to find the solution for the given board // function to find the solution for the given board
for (let i = 0; i < this.size; i++) { for (let i = 0; i < this.size; i++) {
for (let j = 0; j < this.size; j++) { for (let j = 0; j < this.size; j++) {
@ -37,7 +39,7 @@ class OpenKnightTour {
return false return false
} }
solveHelper ([i, j], curr) { solveHelper([i, j], curr) {
// helper function for the main computation // helper function for the main computation
if (this.isComplete()) return true if (this.isComplete()) return true
@ -52,7 +54,7 @@ class OpenKnightTour {
return false return false
} }
printBoard (output = value => console.log(value)) { printBoard(output = (value) => console.log(value)) {
// utility function to display the board // utility function to display the board
for (const row of this.board) { for (const row of this.board) {
let string = '' let string = ''

View File

@ -1,5 +1,5 @@
class NQueens { class NQueens {
constructor (size) { constructor(size) {
if (size < 0) { if (size < 0) {
throw RangeError('Invalid board size') throw RangeError('Invalid board size')
} }
@ -8,7 +8,7 @@ class NQueens {
this.solutionCount = 0 this.solutionCount = 0
} }
isValid ([row, col]) { isValid([row, col]) {
// function to check if the placement of the queen in the given location is valid // function to check if the placement of the queen in the given location is valid
// checking the left of the current row // checking the left of the current row
@ -29,15 +29,15 @@ class NQueens {
return true return true
} }
placeQueen (row, col) { placeQueen(row, col) {
this.board[row][col] = 'Q' this.board[row][col] = 'Q'
} }
removeQueen (row, col) { removeQueen(row, col) {
this.board[row][col] = '.' this.board[row][col] = '.'
} }
solve (col = 0) { solve(col = 0) {
if (col >= this.size) { if (col >= this.size) {
this.solutionCount++ this.solutionCount++
return true return true
@ -54,7 +54,7 @@ class NQueens {
return false return false
} }
printBoard (output = value => console.log(value)) { printBoard(output = (value) => console.log(value)) {
if (!output._isMockFunction) { if (!output._isMockFunction) {
output('\n') output('\n')
} }

View File

@ -21,19 +21,23 @@
* @param grid The grid to check. * @param grid The grid to check.
* @throws TypeError When the given grid is invalid. * @throws TypeError When the given grid is invalid.
*/ */
function validateGrid (grid) { function validateGrid(grid) {
if (!Array.isArray(grid) || grid.length === 0) throw new TypeError('Grid must be a non-empty array') if (!Array.isArray(grid) || grid.length === 0)
throw new TypeError('Grid must be a non-empty array')
const allRowsHaveCorrectLength = grid.every(row => row.length === grid.length) const allRowsHaveCorrectLength = grid.every(
(row) => row.length === grid.length
)
if (!allRowsHaveCorrectLength) throw new TypeError('Grid must be a square') if (!allRowsHaveCorrectLength) throw new TypeError('Grid must be a square')
const allCellsHaveValidValues = grid.every(row => { const allCellsHaveValidValues = grid.every((row) => {
return row.every(cell => cell === 0 || cell === 1) return row.every((cell) => cell === 0 || cell === 1)
}) })
if (!allCellsHaveValidValues) throw new TypeError('Grid must only contain 0s and 1s') if (!allCellsHaveValidValues)
throw new TypeError('Grid must only contain 0s and 1s')
} }
function isSafe (grid, x, y) { function isSafe(grid, x, y) {
const n = grid.length const n = grid.length
return x >= 0 && x < n && y >= 0 && y < n && grid[y][x] === 1 return x >= 0 && x < n && y >= 0 && y < n && grid[y][x] === 1
} }
@ -48,7 +52,7 @@ function isSafe (grid, x, y) {
* @param path The path we took to get from the source cell to the current location. * @param path The path we took to get from the source cell to the current location.
* @returns {string|boolean} Either the path to the target cell or false. * @returns {string|boolean} Either the path to the target cell or false.
*/ */
function getPathPart (grid, x, y, solution, path) { function getPathPart(grid, x, y, solution, path) {
const n = grid.length const n = grid.length
// are we there yet? // are we there yet?
@ -89,7 +93,7 @@ function getPathPart (grid, x, y, solution, path) {
return false return false
} }
function getPath (grid) { function getPath(grid) {
// grid dimensions // grid dimensions
const n = grid.length const n = grid.length
@ -108,7 +112,7 @@ function getPath (grid) {
* Creates an instance of the "rat in a maze" based on a given grid (maze). * Creates an instance of the "rat in a maze" based on a given grid (maze).
*/ */
export class RatInAMaze { export class RatInAMaze {
constructor (grid) { constructor(grid) {
// first, let's do some error checking on the input // first, let's do some error checking on the input
validateGrid(grid) validateGrid(grid)

View File

@ -1,10 +1,10 @@
class Sudoku { class Sudoku {
// Sudoku Class to hold the board and related functions // Sudoku Class to hold the board and related functions
constructor (board) { constructor(board) {
this.board = board this.board = board
} }
findEmptyCell () { findEmptyCell() {
// Find a empty cell in the board (returns [-1, -1] if all cells are filled) // Find a empty cell in the board (returns [-1, -1] if all cells are filled)
for (let i = 0; i < 9; i++) { for (let i = 0; i < 9; i++) {
for (let j = 0; j < 9; j++) { for (let j = 0; j < 9; j++) {
@ -14,7 +14,7 @@ class Sudoku {
return [-1, -1] return [-1, -1]
} }
check ([y, x], value) { check([y, x], value) {
// checks if the value to be added in the board is an acceptable value for the cell // checks if the value to be added in the board is an acceptable value for the cell
// checking through the row // checking through the row
@ -29,8 +29,8 @@ class Sudoku {
// checking through the 3x3 block of the cell // checking through the 3x3 block of the cell
const secRow = Math.floor(y / 3) const secRow = Math.floor(y / 3)
const secCol = Math.floor(x / 3) const secCol = Math.floor(x / 3)
for (let i = (secRow * 3); i < ((secRow * 3) + 3); i++) { for (let i = secRow * 3; i < secRow * 3 + 3; i++) {
for (let j = (secCol * 3); j < ((secCol * 3) + 3); j++) { for (let j = secCol * 3; j < secCol * 3 + 3; j++) {
if (y !== i && x !== j && this.board[i][j] === value) return false if (y !== i && x !== j && this.board[i][j] === value) return false
} }
} }
@ -38,7 +38,7 @@ class Sudoku {
return true return true
} }
solve () { solve() {
const [y, x] = this.findEmptyCell() const [y, x] = this.findEmptyCell()
// checking if the board is complete // checking if the board is complete
@ -56,20 +56,23 @@ class Sudoku {
return false return false
} }
getSection (row, [start, end]) { getSection(row, [start, end]) {
return this.board[row].slice(start, end) return this.board[row].slice(start, end)
} }
printBoard (output = (...v) => console.log(...v)) { printBoard(output = (...v) => console.log(...v)) {
// helper function to display board // helper function to display board
for (let i = 0; i < 9; i++) { for (let i = 0; i < 9; i++) {
if (i % 3 === 0 && i !== 0) { if (i % 3 === 0 && i !== 0) {
output('- - - - - - - - - - - -') output('- - - - - - - - - - - -')
} }
output( output(
...this.getSection(i, [0, 3]), ' | ', ...this.getSection(i, [0, 3]),
...this.getSection(i, [3, 6]), ' | ', ' | ',
...this.getSection(i, [6, 9])) ...this.getSection(i, [3, 6]),
' | ',
...this.getSection(i, [6, 9])
)
} }
} }
} }

View File

@ -3,11 +3,22 @@ import { Combinations } from '../AllCombinationsOfSizeK'
describe('AllCombinationsOfSizeK', () => { describe('AllCombinationsOfSizeK', () => {
it('should return 3x2 matrix solution for n = 3 and k = 2', () => { it('should return 3x2 matrix solution for n = 3 and k = 2', () => {
const test1 = new Combinations(3, 2) const test1 = new Combinations(3, 2)
expect(test1.findCombinations()).toEqual([[1, 2], [1, 3], [2, 3]]) expect(test1.findCombinations()).toEqual([
[1, 2],
[1, 3],
[2, 3]
])
}) })
it('should return 6x2 matrix solution for n = 4 and k = 2', () => { it('should return 6x2 matrix solution for n = 4 and k = 2', () => {
const test2 = new Combinations(4, 2) const test2 = new Combinations(4, 2)
expect(test2.findCombinations()).toEqual([[1, 2], [1, 3], [1, 4], [2, 3], [2, 4], [3, 4]]) expect(test2.findCombinations()).toEqual([
[1, 2],
[1, 3],
[1, 4],
[2, 3],
[2, 4],
[3, 4]
])
}) })
}) })

View File

@ -1,5 +1,11 @@
import { generateParentheses } from '../generateParentheses' import { generateParentheses } from '../generateParentheses'
test('generate all valid parentheses of input 3', () => { test('generate all valid parentheses of input 3', () => {
expect(generateParentheses(3)).toStrictEqual(['((()))', '(()())', '(())()', '()(())', '()()()']) expect(generateParentheses(3)).toStrictEqual([
'((()))',
'(()())',
'(())()',
'()(())',
'()()()'
])
}) })

View File

@ -14,6 +14,8 @@ describe('NQueens', () => {
}) })
it('should throw RangeError for negative size board', () => { it('should throw RangeError for negative size board', () => {
expect(() => { return new NQueens(-1) }).toThrow(RangeError) expect(() => {
return new NQueens(-1)
}).toThrow(RangeError)
}) })
}) })

View File

@ -7,14 +7,18 @@ describe('RatInAMaze', () => {
for (const value of values) { for (const value of values) {
// we deliberately want to check whether this constructor call fails or not // we deliberately want to check whether this constructor call fails or not
// eslint-disable-next-line no-new // eslint-disable-next-line no-new
expect(() => { new RatInAMaze(value) }).toThrow() expect(() => {
new RatInAMaze(value)
}).toThrow()
} }
}) })
it('should fail for an empty array', () => { it('should fail for an empty array', () => {
// we deliberately want to check whether this constructor call fails or not // we deliberately want to check whether this constructor call fails or not
// eslint-disable-next-line no-new // eslint-disable-next-line no-new
expect(() => { new RatInAMaze([]) }).toThrow() expect(() => {
new RatInAMaze([])
}).toThrow()
}) })
it('should fail for a non-square array', () => { it('should fail for a non-square array', () => {
@ -25,7 +29,9 @@ describe('RatInAMaze', () => {
// we deliberately want to check whether this constructor call fails or not // we deliberately want to check whether this constructor call fails or not
// eslint-disable-next-line no-new // eslint-disable-next-line no-new
expect(() => { new RatInAMaze(array) }).toThrow() expect(() => {
new RatInAMaze(array)
}).toThrow()
}) })
it('should fail for arrays containing invalid values', () => { it('should fail for arrays containing invalid values', () => {
@ -34,7 +40,9 @@ describe('RatInAMaze', () => {
for (const value of values) { for (const value of values) {
// we deliberately want to check whether this constructor call fails or not // we deliberately want to check whether this constructor call fails or not
// eslint-disable-next-line no-new // eslint-disable-next-line no-new
expect(() => { new RatInAMaze(value) }).toThrow() expect(() => {
new RatInAMaze(value)
}).toThrow()
} }
}) })
@ -51,13 +59,20 @@ describe('RatInAMaze', () => {
}) })
it('should work for a simple 3x3 maze', () => { it('should work for a simple 3x3 maze', () => {
const maze = new RatInAMaze([[1, 1, 0], [0, 1, 0], [0, 1, 1]]) const maze = new RatInAMaze([
[1, 1, 0],
[0, 1, 0],
[0, 1, 1]
])
expect(maze.solved).toBe(true) expect(maze.solved).toBe(true)
expect(maze.path).toBe('RDDR') expect(maze.path).toBe('RDDR')
}) })
it('should work for a simple 2x2 that can not be solved', () => { it('should work for a simple 2x2 that can not be solved', () => {
const maze = new RatInAMaze([[1, 0], [0, 1]]) const maze = new RatInAMaze([
[1, 0],
[0, 1]
])
expect(maze.solved).toBe(false) expect(maze.solved).toBe(false)
expect(maze.path).toBe('') expect(maze.path).toBe('')
}) })

View File

@ -28,7 +28,9 @@ describe('Sudoku', () => {
it('should create a valid board successfully', () => { it('should create a valid board successfully', () => {
// we deliberately want to check whether this constructor call fails or not // we deliberately want to check whether this constructor call fails or not
// eslint-disable-next-line no-new // eslint-disable-next-line no-new
expect(() => { new Sudoku(data) }).not.toThrow() expect(() => {
new Sudoku(data)
}).not.toThrow()
}) })
it('should find an empty cell', () => { it('should find an empty cell', () => {

View File

@ -7,7 +7,7 @@
*/ */
function BinaryCountSetBits (a) { function BinaryCountSetBits(a) {
'use strict' 'use strict'
// check whether input is an integer, some non-integer number like, 21.1 have non-terminating binary expansions and hence their binary expansion will contain infinite ones, thus the handling of non-integers (including strings,objects etc. as it is meaningless) has been omitted // check whether input is an integer, some non-integer number like, 21.1 have non-terminating binary expansions and hence their binary expansion will contain infinite ones, thus the handling of non-integers (including strings,objects etc. as it is meaningless) has been omitted

View File

@ -12,6 +12,6 @@
* const result = isPowerOfFour(16); // Returns true (16 is 4^2) * const result = isPowerOfFour(16); // Returns true (16 is 4^2)
* const result2 = isPowerOfFour(5); // Returns false (5 is not a power of four) * const result2 = isPowerOfFour(5); // Returns false (5 is not a power of four)
*/ */
const isPowerOfFour = (n) => ((n > 0) && ((n & n - 1) === 0) && (n % 3 === 1)) const isPowerOfFour = (n) => n > 0 && (n & (n - 1)) === 0 && n % 3 === 1
export { isPowerOfFour } export { isPowerOfFour }

View File

@ -94,8 +94,8 @@ Be confident that your code works. When was the last time you committed a code c
your app stopped working? Mine was last week. Writing tests for our Algorithms will help us ensure the implementations your app stopped working? Mine was last week. Writing tests for our Algorithms will help us ensure the implementations
are airtight even after multiple fixes and code changes. are airtight even after multiple fixes and code changes.
We use [Jest](https://jestjs.io/) to run unit tests on our algorithms. It provides a very readable and expressive way to We use [Vitest](https://vitest.dev/) to run unit tests on our algorithms. It provides a very readable and expressive
structure your test code. way to structure your test code.
It is advised that the algorithm file (module) does not contain any "live" code but rather just exports the function(s) It is advised that the algorithm file (module) does not contain any "live" code but rather just exports the function(s)
needed to execute the algorithm. Your test code can import those function(s), call them with the appropriate parameters needed to execute the algorithm. Your test code can import those function(s), call them with the appropriate parameters
@ -122,34 +122,23 @@ If you want to save some time and just run a specific test:
npm test -- koch npm test -- koch
``` ```
You can also start Jest in "watch" mode: You can also start Vitest in "watch" mode:
```bash ```bash
npm test -- --watchAll npm test-watch
```
We also prepared a helper script that runs tests only for changed files:
```bash
npm run test-changed
``` ```
This will run all tests and watch source and test files for changes. When a change is made, the tests will run again. This will run all tests and watch source and test files for changes. When a change is made, the tests will run again.
#### Coding Style #### Coding Style
To maximize the readability and correctness of our code, we require that new submissions follow the For consistency and readability, we require that new submissions follow the [Prettier Style](https://prettier.io/).
[JavaScript Standard Style](https://standardjs.com/). Before committing, please format your code automatically using Prettier by running the following command:
Before committing, please run:
```bash ```bash
npm run style npm run style
``` ```
In order to apply the coding style (where it can be done automatically). If an error is shown, please figure out what's
wrong, fix it and run standard again.
A few (but not all) of the things to keep in mind: A few (but not all) of the things to keep in mind:
- Use camelCase with the leading character as lowercase for identifier names (variables and functions). - Use camelCase with the leading character as lowercase for identifier names (variables and functions).

View File

@ -1,5 +1,5 @@
class CacheNode { class CacheNode {
constructor (key, value, frequency) { constructor(key, value, frequency) {
this.key = key this.key = key
this.value = value this.value = value
this.frequency = frequency this.frequency = frequency
@ -10,15 +10,19 @@ class CacheNode {
// This frequency map class will act like javascript Map DS with more two custom method refresh & insert // This frequency map class will act like javascript Map DS with more two custom method refresh & insert
class FrequencyMap extends Map { class FrequencyMap extends Map {
static get [Symbol.species] () { return Map } // for using Symbol.species we can access Map constructor @see -> https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/@@species static get [Symbol.species]() {
get [Symbol.toStringTag] () { return '' } return Map
} // for using Symbol.species we can access Map constructor @see -> https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/@@species
get [Symbol.toStringTag]() {
return ''
}
/** /**
* @method refresh * @method refresh
* @description - It's revive a CacheNode, increment of this nodes frequency and refresh the frequencyMap via new incremented nodes frequency * @description - It's revive a CacheNode, increment of this nodes frequency and refresh the frequencyMap via new incremented nodes frequency
* @param {CacheNode} node * @param {CacheNode} node
*/ */
refresh (node) { refresh(node) {
const { frequency } = node const { frequency } = node
const freqSet = this.get(frequency) const freqSet = this.get(frequency)
freqSet.delete(node) freqSet.delete(node)
@ -33,7 +37,7 @@ class FrequencyMap extends Map {
* @description - Add new CacheNode into HashSet by the frequency * @description - Add new CacheNode into HashSet by the frequency
* @param {CacheNode} node * @param {CacheNode} node
*/ */
insert (node) { insert(node) {
const { frequency } = node const { frequency } = node
if (!this.has(frequency)) { if (!this.has(frequency)) {
@ -52,7 +56,7 @@ class LFUCache {
* @param {number} capacity - The range of LFUCache * @param {number} capacity - The range of LFUCache
* @returns {LFUCache} - sealed * @returns {LFUCache} - sealed
*/ */
constructor (capacity) { constructor(capacity) {
this.#capacity = capacity this.#capacity = capacity
this.#frequencyMap = new FrequencyMap() this.#frequencyMap = new FrequencyMap()
this.misses = 0 this.misses = 0
@ -66,7 +70,7 @@ class LFUCache {
* Get the capacity of the LFUCache * Get the capacity of the LFUCache
* @returns {number} * @returns {number}
*/ */
get capacity () { get capacity() {
return this.#capacity return this.#capacity
} }
@ -74,14 +78,14 @@ class LFUCache {
* Get the current size of LFUCache * Get the current size of LFUCache
* @returns {number} * @returns {number}
*/ */
get size () { get size() {
return this.cache.size return this.cache.size
} }
/** /**
* Set the capacity of the LFUCache if you decrease the capacity its removed CacheNodes following the LFU - least frequency used * Set the capacity of the LFUCache if you decrease the capacity its removed CacheNodes following the LFU - least frequency used
*/ */
set capacity (newCapacity) { set capacity(newCapacity) {
if (this.#capacity > newCapacity) { if (this.#capacity > newCapacity) {
let diff = this.#capacity - newCapacity // get the decrement number of capacity let diff = this.#capacity - newCapacity // get the decrement number of capacity
@ -95,7 +99,7 @@ class LFUCache {
this.#capacity = newCapacity this.#capacity = newCapacity
} }
get info () { get info() {
return Object.freeze({ return Object.freeze({
misses: this.misses, misses: this.misses,
hits: this.hits, hits: this.hits,
@ -105,7 +109,7 @@ class LFUCache {
}) })
} }
get leastFrequency () { get leastFrequency() {
const freqCacheIterator = this.#frequencyMap.keys() const freqCacheIterator = this.#frequencyMap.keys()
let leastFrequency = freqCacheIterator.next().value || null let leastFrequency = freqCacheIterator.next().value || null
@ -117,7 +121,7 @@ class LFUCache {
return leastFrequency return leastFrequency
} }
#removeCacheNode () { #removeCacheNode() {
const leastFreqSet = this.#frequencyMap.get(this.leastFrequency) const leastFreqSet = this.#frequencyMap.get(this.leastFrequency)
// Select the least recently used node from the least Frequency set // Select the least recently used node from the least Frequency set
const LFUNode = leastFreqSet.values().next().value const LFUNode = leastFreqSet.values().next().value
@ -131,7 +135,7 @@ class LFUCache {
* @param {any} key * @param {any} key
* @returns {boolean} * @returns {boolean}
*/ */
has (key) { has(key) {
key = String(key) // converted to string key = String(key) // converted to string
return this.cache.has(key) return this.cache.has(key)
@ -143,7 +147,7 @@ class LFUCache {
* @param {string} key * @param {string} key
* @returns {any} * @returns {any}
*/ */
get (key) { get(key) {
key = String(key) // converted to string key = String(key) // converted to string
if (this.cache.has(key)) { if (this.cache.has(key)) {
@ -167,7 +171,7 @@ class LFUCache {
* @param {number} frequency * @param {number} frequency
* @returns {LFUCache} * @returns {LFUCache}
*/ */
set (key, value, frequency = 1) { set(key, value, frequency = 1) {
key = String(key) // converted to string key = String(key) // converted to string
if (this.#capacity === 0) { if (this.#capacity === 0) {
@ -202,7 +206,7 @@ class LFUCache {
* @param {JSON} json * @param {JSON} json
* @returns {LFUCache} - merged * @returns {LFUCache} - merged
*/ */
parse (json) { parse(json) {
const { misses, hits, cache } = JSON.parse(json) const { misses, hits, cache } = JSON.parse(json)
this.misses += misses ?? 0 this.misses += misses ?? 0
@ -221,7 +225,7 @@ class LFUCache {
* @description - This method cleared the whole LFUCache * @description - This method cleared the whole LFUCache
* @returns {LFUCache} * @returns {LFUCache}
*/ */
clear () { clear() {
this.cache.clear() this.cache.clear()
this.#frequencyMap.clear() this.#frequencyMap.clear()
@ -234,7 +238,7 @@ class LFUCache {
* @param {number} indent * @param {number} indent
* @returns {string} - JSON * @returns {string} - JSON
*/ */
toString (indent) { toString(indent) {
const replacer = (_, value) => { const replacer = (_, value) => {
if (value instanceof Set) { if (value instanceof Set) {
return [...value] return [...value]

View File

@ -6,7 +6,7 @@ class LRUCache {
* @param {number} capacity - the capacity of LRUCache * @param {number} capacity - the capacity of LRUCache
* @returns {LRUCache} - sealed * @returns {LRUCache} - sealed
*/ */
constructor (capacity) { constructor(capacity) {
if (!Number.isInteger(capacity) || capacity < 0) { if (!Number.isInteger(capacity) || capacity < 0) {
throw new TypeError('Invalid capacity') throw new TypeError('Invalid capacity')
} }
@ -19,7 +19,7 @@ class LRUCache {
return Object.seal(this) return Object.seal(this)
} }
get info () { get info() {
return Object.freeze({ return Object.freeze({
misses: this.misses, misses: this.misses,
hits: this.hits, hits: this.hits,
@ -28,15 +28,15 @@ class LRUCache {
}) })
} }
get size () { get size() {
return this.cache.size return this.cache.size
} }
get capacity () { get capacity() {
return this.#capacity return this.#capacity
} }
set capacity (newCapacity) { set capacity(newCapacity) {
if (newCapacity < 0) { if (newCapacity < 0) {
throw new RangeError('Capacity should be greater than 0') throw new RangeError('Capacity should be greater than 0')
} }
@ -55,7 +55,7 @@ class LRUCache {
/** /**
* delete oldest key existing in map by the help of iterator * delete oldest key existing in map by the help of iterator
*/ */
#removeLeastRecentlyUsed () { #removeLeastRecentlyUsed() {
this.cache.delete(this.cache.keys().next().value) this.cache.delete(this.cache.keys().next().value)
} }
@ -63,7 +63,7 @@ class LRUCache {
* @param {string} key * @param {string} key
* @returns {*} * @returns {*}
*/ */
has (key) { has(key) {
key = String(key) key = String(key)
return this.cache.has(key) return this.cache.has(key)
@ -73,7 +73,7 @@ class LRUCache {
* @param {string} key * @param {string} key
* @param {*} value * @param {*} value
*/ */
set (key, value) { set(key, value) {
key = String(key) key = String(key)
// Sets the value for the input key and if the key exists it updates the existing key // Sets the value for the input key and if the key exists it updates the existing key
if (this.size === this.capacity) { if (this.size === this.capacity) {
@ -87,7 +87,7 @@ class LRUCache {
* @param {string} key * @param {string} key
* @returns {*} * @returns {*}
*/ */
get (key) { get(key) {
key = String(key) key = String(key)
// Returns the value for the input key. Returns null if key is not present in cache // Returns the value for the input key. Returns null if key is not present in cache
if (this.cache.has(key)) { if (this.cache.has(key)) {
@ -109,7 +109,7 @@ class LRUCache {
* @param {JSON} json * @param {JSON} json
* @returns {LRUCache} * @returns {LRUCache}
*/ */
parse (json) { parse(json) {
const { misses, hits, cache } = JSON.parse(json) const { misses, hits, cache } = JSON.parse(json)
this.misses += misses ?? 0 this.misses += misses ?? 0
@ -126,7 +126,7 @@ class LRUCache {
* @param {number} indent * @param {number} indent
* @returns {JSON} - string * @returns {JSON} - string
*/ */
toString (indent) { toString(indent) {
const replacer = (_, value) => { const replacer = (_, value) => {
if (value instanceof Set) { if (value instanceof Set) {
return [...value] return [...value]

View File

@ -15,11 +15,13 @@
*/ */
const memoize = (func, cache = new Map()) => { const memoize = (func, cache = new Map()) => {
const jsonReplacer = (_, value) => { const jsonReplacer = (_, value) => {
if (value instanceof Set) { // if the value is Set it's converted to Array cause JSON.stringify can't convert Set if (value instanceof Set) {
// if the value is Set it's converted to Array cause JSON.stringify can't convert Set
return [...value] return [...value]
} }
if (value instanceof Map) { // if the value is Map it's converted to Object cause JSON.stringify can't convert Map if (value instanceof Map) {
// if the value is Map it's converted to Object cause JSON.stringify can't convert Map
return Object.fromEntries(value) return Object.fromEntries(value)
} }

View File

@ -36,7 +36,8 @@ describe('Testing LFUCache class', () => {
leastFrequency: 2 leastFrequency: 2
}) })
const json = '{"misses":3,"hits":6,"cache":{"2":{"key":"2","value":2,"frequency":4},"4":{"key":"4","value":4,"frequency":2}}}' const json =
'{"misses":3,"hits":6,"cache":{"2":{"key":"2","value":2,"frequency":4},"4":{"key":"4","value":4,"frequency":2}}}'
expect(cache.toString()).toBe(json) expect(cache.toString()).toBe(json)
const cacheInstance = cache.parse(json) // again merge the json const cacheInstance = cache.parse(json) // again merge the json
@ -45,7 +46,8 @@ describe('Testing LFUCache class', () => {
cache.capacity = 1 // decrease the capacity cache.capacity = 1 // decrease the capacity
expect(cache.info).toEqual({ // after merging the info expect(cache.info).toEqual({
// after merging the info
misses: 6, misses: 6,
hits: 12, hits: 12,
capacity: 1, capacity: 1,

View File

@ -43,11 +43,7 @@ describe('Testing Memoize', () => {
it('expects the union function to use the cache on the second call', () => { it('expects the union function to use the cache on the second call', () => {
const memoUnion = memoize(union) const memoUnion = memoize(union)
const inputs = [ const inputs = [new Set([1, 2, 3]), new Set([4, 3, 2]), new Set([5, 3, 6])]
new Set([1, 2, 3]),
new Set([4, 3, 2]),
new Set([5, 3, 6])
]
expect(memoUnion(...inputs)).toEqual(new Set([1, 2, 3, 4, 5, 6])) expect(memoUnion(...inputs)).toEqual(new Set([1, 2, 3, 4, 5, 6]))
expect(memoUnion(...inputs)).toEqual(union(...inputs)) expect(memoUnion(...inputs)).toEqual(union(...inputs))

View File

@ -31,7 +31,5 @@ export const fibonacciCache = (n, cache = null) => {
* @return {new Set} * @return {new Set}
*/ */
export const union = (...sets) => { export const union = (...sets) => {
return new Set( return new Set(sets.reduce((flatArray, set) => [...flatArray, ...set], []))
sets.reduce((flatArray, set) => [...flatArray, ...set], [])
)
} }

View File

@ -11,7 +11,7 @@ The Game of Life is a cellular automaton devised by the British mathematician Jo
/** /**
* Generates the next generation for a given state of Conway's Game of Life. * Generates the next generation for a given state of Conway's Game of Life.
*/ */
export function newGeneration (cells) { export function newGeneration(cells) {
const nextGeneration = [] const nextGeneration = []
for (let i = 0; i < cells.length; i++) { for (let i = 0; i < cells.length; i++) {
const nextGenerationRow = [] const nextGenerationRow = []
@ -20,12 +20,14 @@ export function newGeneration (cells) {
let neighbourCount = 0 let neighbourCount = 0
if (i > 0 && j > 0) neighbourCount += cells[i - 1][j - 1] if (i > 0 && j > 0) neighbourCount += cells[i - 1][j - 1]
if (i > 0) neighbourCount += cells[i - 1][j] if (i > 0) neighbourCount += cells[i - 1][j]
if (i > 0 && j < cells[i].length - 1) neighbourCount += cells[i - 1][j + 1] if (i > 0 && j < cells[i].length - 1)
neighbourCount += cells[i - 1][j + 1]
if (j > 0) neighbourCount += cells[i][j - 1] if (j > 0) neighbourCount += cells[i][j - 1]
if (j < cells[i].length - 1) neighbourCount += cells[i][j + 1] if (j < cells[i].length - 1) neighbourCount += cells[i][j + 1]
if (i < cells.length - 1 && j > 0) neighbourCount += cells[i + 1][j - 1] if (i < cells.length - 1 && j > 0) neighbourCount += cells[i + 1][j - 1]
if (i < cells.length - 1) neighbourCount += cells[i + 1][j] if (i < cells.length - 1) neighbourCount += cells[i + 1][j]
if (i < cells.length - 1 && j < cells[i].length - 1) neighbourCount += cells[i + 1][j + 1] if (i < cells.length - 1 && j < cells[i].length - 1)
neighbourCount += cells[i + 1][j + 1]
// Decide whether the cell is alive or dead // Decide whether the cell is alive or dead
const alive = cells[i][j] === 1 const alive = cells[i][j] === 1

View File

@ -64,20 +64,26 @@
* @param {number} rule The current rule of the Elementary Cellular Automata simulation. Must be an integer between 0 and 255 inclusive * @param {number} rule The current rule of the Elementary Cellular Automata simulation. Must be an integer between 0 and 255 inclusive
* @returns {(0 | 1)[]} The next generation according to the inputted rule * @returns {(0 | 1)[]} The next generation according to the inputted rule
*/ */
export function getNextElementaryGeneration (generation, rule) { export function getNextElementaryGeneration(generation, rule) {
const NUM_ELEMENTARY_NEIGHBORHOOD_STATES = 8 const NUM_ELEMENTARY_NEIGHBORHOOD_STATES = 8
const MIN_RULE = 0 const MIN_RULE = 0
const MAX_RULE = 255 const MAX_RULE = 255
if (!Number.isInteger(rule)) { if (!Number.isInteger(rule)) {
throw new Error(`Rule must be an integer between the values 0 and 255 (got ${rule})`) throw new Error(
`Rule must be an integer between the values 0 and 255 (got ${rule})`
)
} }
if (rule < MIN_RULE || rule > MAX_RULE) { if (rule < MIN_RULE || rule > MAX_RULE) {
throw new RangeError(`Rule must be an integer between the values 0 and 255 (got ${rule})`) throw new RangeError(
`Rule must be an integer between the values 0 and 255 (got ${rule})`
)
} }
const binaryRule = rule.toString(2).padStart(NUM_ELEMENTARY_NEIGHBORHOOD_STATES, '0') const binaryRule = rule
const ruleData = binaryRule.split('').map(bit => Number.parseInt(bit)) // note that ruleData[0] represents "all alive" while ruleData[7] represents "all dead" .toString(2)
.padStart(NUM_ELEMENTARY_NEIGHBORHOOD_STATES, '0')
const ruleData = binaryRule.split('').map((bit) => Number.parseInt(bit)) // note that ruleData[0] represents "all alive" while ruleData[7] represents "all dead"
const output = new Array(generation.length) const output = new Array(generation.length)
const LEFT_DEAD = 4 // 100 in binary const LEFT_DEAD = 4 // 100 in binary
const MIDDLE_DEAD = 2 // 010 in binary const MIDDLE_DEAD = 2 // 010 in binary

View File

@ -2,7 +2,16 @@ import { newGeneration } from '../ConwaysGameOfLife'
describe('newGeneration', () => { describe('newGeneration', () => {
it('should produce the next generation according to the rules', () => { it('should produce the next generation according to the rules', () => {
expect(newGeneration([[0, 1, 0], [0, 1, 0], [0, 1, 0]])) expect(
.toEqual([[0, 0, 0], [1, 1, 1], [0, 0, 0]]) newGeneration([
[0, 1, 0],
[0, 1, 0],
[0, 1, 0]
])
).toEqual([
[0, 0, 0],
[1, 1, 1],
[0, 0, 0]
])
}) })
}) })

View File

@ -3,91 +3,137 @@ import { getNextElementaryGeneration } from '../Elementary'
describe('Elementary Cellular Automata', () => { describe('Elementary Cellular Automata', () => {
describe('Rule Errors', () => { describe('Rule Errors', () => {
it('Correct', () => { it('Correct', () => {
expect(() => getNextElementaryGeneration([0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0], 128)).not.toThrow() expect(() =>
getNextElementaryGeneration([0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0], 128)
).not.toThrow()
}) })
it('Less than 0', () => { it('Less than 0', () => {
expect(() => getNextElementaryGeneration([0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0], -1)).toThrow() expect(() =>
getNextElementaryGeneration([0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0], -1)
).toThrow()
}) })
it('Greater than 255', () => { it('Greater than 255', () => {
expect(() => getNextElementaryGeneration([0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0], 256)).toThrow() expect(() =>
getNextElementaryGeneration([0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0], 256)
).toThrow()
}) })
it('Decimal', () => { it('Decimal', () => {
expect(() => getNextElementaryGeneration([0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0], 100.4)).toThrow() expect(() =>
getNextElementaryGeneration([0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0], 100.4)
).toThrow()
}) })
}) })
describe('Rule 54 Iterations', () => { describe('Rule 54 Iterations', () => {
it('Generation 1', () => { it('Generation 1', () => {
expect(getNextElementaryGeneration([0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0], 54)).toEqual([0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0]) expect(
getNextElementaryGeneration([0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0], 54)
).toEqual([0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0])
}) })
it('Generation 2', () => { it('Generation 2', () => {
expect(getNextElementaryGeneration([0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0], 54)).toEqual([0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0]) expect(
getNextElementaryGeneration([0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0], 54)
).toEqual([0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0])
}) })
it('Generation 3', () => { it('Generation 3', () => {
expect(getNextElementaryGeneration([0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0], 54)).toEqual([0, 0, 1, 1, 1, 0, 1, 1, 1, 0, 0]) expect(
getNextElementaryGeneration([0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0], 54)
).toEqual([0, 0, 1, 1, 1, 0, 1, 1, 1, 0, 0])
}) })
it('Generation 4', () => { it('Generation 4', () => {
expect(getNextElementaryGeneration([0, 0, 1, 1, 1, 0, 1, 1, 1, 0, 0], 54)).toEqual([0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0]) expect(
getNextElementaryGeneration([0, 0, 1, 1, 1, 0, 1, 1, 1, 0, 0], 54)
).toEqual([0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0])
}) })
}) })
describe('Rule 222 Iterations', () => { describe('Rule 222 Iterations', () => {
it('Generation 1', () => { it('Generation 1', () => {
expect(getNextElementaryGeneration([0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0], 222)).toEqual([0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0]) expect(
getNextElementaryGeneration([0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0], 222)
).toEqual([0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0])
}) })
it('Generation 2', () => { it('Generation 2', () => {
expect(getNextElementaryGeneration([0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0], 222)).toEqual([0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0]) expect(
getNextElementaryGeneration([0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0], 222)
).toEqual([0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0])
}) })
it('Generation 3', () => { it('Generation 3', () => {
expect(getNextElementaryGeneration([0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0], 222)).toEqual([0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0]) expect(
getNextElementaryGeneration([0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0], 222)
).toEqual([0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0])
}) })
it('Generation 4', () => { it('Generation 4', () => {
expect(getNextElementaryGeneration([0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0], 222)).toEqual([0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0]) expect(
getNextElementaryGeneration([0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0], 222)
).toEqual([0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0])
}) })
}) })
describe('Rule 60 Iterations', () => { describe('Rule 60 Iterations', () => {
it('Generation 1', () => { it('Generation 1', () => {
expect(getNextElementaryGeneration([0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0], 60)).toEqual([0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0]) expect(
getNextElementaryGeneration([0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0], 60)
).toEqual([0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0])
}) })
it('Generation 2', () => { it('Generation 2', () => {
expect(getNextElementaryGeneration([0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0], 60)).toEqual([0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0]) expect(
getNextElementaryGeneration([0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0], 60)
).toEqual([0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0])
}) })
it('Generation 3', () => { it('Generation 3', () => {
expect(getNextElementaryGeneration([0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0], 60)).toEqual([0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0]) expect(
getNextElementaryGeneration([0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0], 60)
).toEqual([0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0])
}) })
it('Generation 4', () => { it('Generation 4', () => {
expect(getNextElementaryGeneration([0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0], 60)).toEqual([0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0]) expect(
getNextElementaryGeneration([0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0], 60)
).toEqual([0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0])
}) })
}) })
describe('Rule 90 Iterations', () => { describe('Rule 90 Iterations', () => {
it('Generation 1', () => { it('Generation 1', () => {
expect(getNextElementaryGeneration([0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0], 90)).toEqual([0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0]) expect(
getNextElementaryGeneration([0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0], 90)
).toEqual([0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0])
}) })
it('Generation 2', () => { it('Generation 2', () => {
expect(getNextElementaryGeneration([0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0], 90)).toEqual([0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0]) expect(
getNextElementaryGeneration([0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0], 90)
).toEqual([0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0])
}) })
it('Generation 3', () => { it('Generation 3', () => {
expect(getNextElementaryGeneration([0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0], 90)).toEqual([0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0]) expect(
getNextElementaryGeneration([0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0], 90)
).toEqual([0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0])
}) })
it('Generation 4', () => { it('Generation 4', () => {
expect(getNextElementaryGeneration([0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0], 90)).toEqual([0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0]) expect(
getNextElementaryGeneration([0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0], 90)
).toEqual([0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0])
}) })
}) })
describe('Rule 30 Iterations', () => { describe('Rule 30 Iterations', () => {
it('Generation 1', () => { it('Generation 1', () => {
expect(getNextElementaryGeneration([0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0], 30)).toEqual([0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0]) expect(
getNextElementaryGeneration([0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0], 30)
).toEqual([0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0])
}) })
it('Generation 2', () => { it('Generation 2', () => {
expect(getNextElementaryGeneration([0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0], 30)).toEqual([0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0]) expect(
getNextElementaryGeneration([0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0], 30)
).toEqual([0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0])
}) })
it('Generation 3', () => { it('Generation 3', () => {
expect(getNextElementaryGeneration([0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0], 30)).toEqual([0, 0, 1, 1, 0, 1, 1, 1, 1, 0, 0]) expect(
getNextElementaryGeneration([0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0], 30)
).toEqual([0, 0, 1, 1, 0, 1, 1, 1, 1, 0, 0])
}) })
}) })
}) })

View File

@ -13,7 +13,7 @@ const key = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
* @param {Number} m - Modulos value * @param {Number} m - Modulos value
* @return {Number} Return n mod m * @return {Number} Return n mod m
*/ */
function mod (n, m) { function mod(n, m) {
return ((n % m) + m) % m return ((n % m) + m) % m
} }
@ -23,7 +23,7 @@ function mod (n, m) {
* @param {Number} m - Modulos value * @param {Number} m - Modulos value
* @return {Number} Return modular multiplicative inverse of coefficient a and modulos m * @return {Number} Return modular multiplicative inverse of coefficient a and modulos m
*/ */
function inverseMod (a, m) { function inverseMod(a, m) {
for (let x = 1; x < m; x++) { for (let x = 1; x < m; x++) {
if (mod(a * x, m) === 1) return x if (mod(a * x, m) === 1) return x
} }
@ -36,7 +36,7 @@ function inverseMod (a, m) {
* @param {Number} b - B coefficient to be checked * @param {Number} b - B coefficient to be checked
* @return {Boolean} Result of the checking * @return {Boolean} Result of the checking
*/ */
function isCorrectFormat (str, a, b) { function isCorrectFormat(str, a, b) {
if (typeof a !== 'number' || typeof b !== 'number') { if (typeof a !== 'number' || typeof b !== 'number') {
throw new TypeError('Coefficient a, b should be number') throw new TypeError('Coefficient a, b should be number')
} }
@ -57,8 +57,8 @@ function isCorrectFormat (str, a, b) {
* @param {String} char - Character index to be found * @param {String} char - Character index to be found
* @return {Boolean} Character index * @return {Boolean} Character index
*/ */
function findCharIndex (char) { function findCharIndex(char) {
return char.toUpperCase().charCodeAt(0) - ('A').charCodeAt(0) return char.toUpperCase().charCodeAt(0) - 'A'.charCodeAt(0)
} }
/** /**
@ -69,7 +69,7 @@ function findCharIndex (char) {
* @return {String} result - Encrypted string * @return {String} result - Encrypted string
*/ */
function encrypt (str, a, b) { function encrypt(str, a, b) {
let result = '' let result = ''
if (isCorrectFormat(str, a, b)) { if (isCorrectFormat(str, a, b)) {
for (let x = 0; x < str.length; x++) { for (let x = 0; x < str.length; x++) {
@ -88,7 +88,7 @@ function encrypt (str, a, b) {
* @param {Number} b - B coefficient * @param {Number} b - B coefficient
* @return {String} result - Decrypted string * @return {String} result - Decrypted string
*/ */
function decrypt (str, a, b) { function decrypt(str, a, b) {
let result = '' let result = ''
if (isCorrectFormat(str, a, b)) { if (isCorrectFormat(str, a, b)) {
str = str.split(' ') str = str.split(' ')

View File

@ -2,7 +2,8 @@
Find and retrieve the encryption key automatically Find and retrieve the encryption key automatically
Note: This is a draft version, please help to modify, Thanks! Note: This is a draft version, please help to modify, Thanks!
******************************************************/ ******************************************************/
function keyFinder (str) { // str is used to get the input of encrypted string function keyFinder(str) {
// str is used to get the input of encrypted string
const wordBank = [ const wordBank = [
'I ', 'I ',
'You ', 'You ',
@ -27,13 +28,15 @@ function keyFinder (str) { // str is used to get the input of encrypted string
' may ', ' may ',
'May ', 'May ',
' be ', ' be ',
'Be '] 'Be '
]
// let wordbankelementCounter = 0; // let wordbankelementCounter = 0;
// let key = 0; // return zero means the key can not be found // let key = 0; // return zero means the key can not be found
const inStr = str.toString() // convert the input to String const inStr = str.toString() // convert the input to String
let outStr = '' // store the output value let outStr = '' // store the output value
let outStrElement = '' // temporary store the word inside the outStr, it is used for comparison let outStrElement = '' // temporary store the word inside the outStr, it is used for comparison
for (let k = 0; k < 26; k++) { // try the number of key shifted, the sum of character from a-z or A-Z is 26 for (let k = 0; k < 26; k++) {
// try the number of key shifted, the sum of character from a-z or A-Z is 26
outStr = caesarCipherEncodeAndDecodeEngine(inStr, k) // use the encryption engine to decrypt the input string outStr = caesarCipherEncodeAndDecodeEngine(inStr, k) // use the encryption engine to decrypt the input string
// loop through the whole input string // loop through the whole input string
@ -57,7 +60,7 @@ function keyFinder (str) { // str is used to get the input of encrypted string
} }
/* this sub-function is used to assist the keyFinder to find the key */ /* this sub-function is used to assist the keyFinder to find the key */
function caesarCipherEncodeAndDecodeEngine (inStr, numShifted) { function caesarCipherEncodeAndDecodeEngine(inStr, numShifted) {
const shiftNum = numShifted const shiftNum = numShifted
let charCode = 0 let charCode = 0
let outStr = '' let outStr = ''
@ -69,7 +72,7 @@ function caesarCipherEncodeAndDecodeEngine (inStr, numShifted) {
shiftedCharCode = charCode + shiftNum shiftedCharCode = charCode + shiftNum
result = charCode result = charCode
if ((charCode >= 48 && charCode <= 57)) { if (charCode >= 48 && charCode <= 57) {
if (shiftedCharCode < 48) { if (shiftedCharCode < 48) {
let diff = Math.abs(48 - 1 - shiftedCharCode) % 10 let diff = Math.abs(48 - 1 - shiftedCharCode) % 10
@ -95,11 +98,11 @@ function caesarCipherEncodeAndDecodeEngine (inStr, numShifted) {
result = shiftedCharCode result = shiftedCharCode
} }
} else if ((charCode >= 65 && charCode <= 90)) { } else if (charCode >= 65 && charCode <= 90) {
if (shiftedCharCode <= 64) { if (shiftedCharCode <= 64) {
let diff = Math.abs(65 - 1 - shiftedCharCode) % 26 let diff = Math.abs(65 - 1 - shiftedCharCode) % 26
while ((diff % 26) >= 26) { while (diff % 26 >= 26) {
diff = diff % 26 diff = diff % 26
} }
shiftedCharCode = 90 - diff shiftedCharCode = 90 - diff
@ -109,17 +112,17 @@ function caesarCipherEncodeAndDecodeEngine (inStr, numShifted) {
} else if (shiftedCharCode > 90) { } else if (shiftedCharCode > 90) {
let diff = Math.abs(shiftedCharCode - 1 - 90) % 26 let diff = Math.abs(shiftedCharCode - 1 - 90) % 26
while ((diff % 26) >= 26) { while (diff % 26 >= 26) {
diff = diff % 26 diff = diff % 26
} }
shiftedCharCode = 65 + diff shiftedCharCode = 65 + diff
result = shiftedCharCode result = shiftedCharCode
} }
} else if ((charCode >= 97 && charCode <= 122)) { } else if (charCode >= 97 && charCode <= 122) {
if (shiftedCharCode <= 96) { if (shiftedCharCode <= 96) {
let diff = Math.abs(97 - 1 - shiftedCharCode) % 26 let diff = Math.abs(97 - 1 - shiftedCharCode) % 26
while ((diff % 26) >= 26) { while (diff % 26 >= 26) {
diff = diff % 26 diff = diff % 26
} }
shiftedCharCode = 122 - diff shiftedCharCode = 122 - diff
@ -129,7 +132,7 @@ function caesarCipherEncodeAndDecodeEngine (inStr, numShifted) {
} else if (shiftedCharCode > 122) { } else if (shiftedCharCode > 122) {
let diff = Math.abs(shiftedCharCode - 1 - 122) % 26 let diff = Math.abs(shiftedCharCode - 1 - 122) % 26
while ((diff % 26) >= 26) { while (diff % 26 >= 26) {
diff = diff % 26 diff = diff % 26
} }
shiftedCharCode = 97 + diff shiftedCharCode = 97 + diff

View File

@ -16,9 +16,36 @@
* Non alphabetical characters (space, exclamation mark, ...) are kept as they are * Non alphabetical characters (space, exclamation mark, ...) are kept as they are
*/ */
const alphabet = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'] const alphabet = [
'a',
'b',
'c',
'd',
'e',
'f',
'g',
'h',
'i',
'j',
'k',
'l',
'm',
'n',
'o',
'p',
'q',
'r',
's',
't',
'u',
'v',
'w',
'x',
'y',
'z'
]
function checkKeywordValidity (keyword) { function checkKeywordValidity(keyword) {
keyword.split('').forEach((char, index) => { keyword.split('').forEach((char, index) => {
const rest = keyword.slice(0, index) + keyword.slice(index + 1) const rest = keyword.slice(0, index) + keyword.slice(index + 1)
if (rest.indexOf(char) !== -1) { if (rest.indexOf(char) !== -1) {
@ -28,7 +55,7 @@ function checkKeywordValidity (keyword) {
return true return true
} }
function getEncryptedAlphabet (keyword) { function getEncryptedAlphabet(keyword) {
const encryptedAlphabet = keyword.split('') const encryptedAlphabet = keyword.split('')
alphabet.forEach((char) => { alphabet.forEach((char) => {
if (encryptedAlphabet.indexOf(char) === -1) { if (encryptedAlphabet.indexOf(char) === -1) {
@ -38,17 +65,20 @@ function getEncryptedAlphabet (keyword) {
return encryptedAlphabet return encryptedAlphabet
} }
function translate (sourceAlphabet, targetAlphabet, message) { function translate(sourceAlphabet, targetAlphabet, message) {
return message.split('').reduce((encryptedMessage, char) => { return message.split('').reduce((encryptedMessage, char) => {
const isUpperCase = char === char.toUpperCase() const isUpperCase = char === char.toUpperCase()
const encryptedCharIndex = sourceAlphabet.indexOf(char.toLowerCase()) const encryptedCharIndex = sourceAlphabet.indexOf(char.toLowerCase())
const encryptedChar = encryptedCharIndex !== -1 ? targetAlphabet[encryptedCharIndex] : char const encryptedChar =
encryptedMessage += isUpperCase ? encryptedChar.toUpperCase() : encryptedChar encryptedCharIndex !== -1 ? targetAlphabet[encryptedCharIndex] : char
encryptedMessage += isUpperCase
? encryptedChar.toUpperCase()
: encryptedChar
return encryptedMessage return encryptedMessage
}, '') }, '')
} }
function checkInputs (keyword, message) { function checkInputs(keyword, message) {
if (!keyword || !message) { if (!keyword || !message) {
throw new Error('Both keyword and message must be specified') throw new Error('Both keyword and message must be specified')
} }
@ -58,14 +88,22 @@ function checkInputs (keyword, message) {
} }
} }
function encrypt (keyword, message) { function encrypt(keyword, message) {
checkInputs(keyword, message) checkInputs(keyword, message)
return translate(alphabet, getEncryptedAlphabet(keyword.toLowerCase()), message) return translate(
alphabet,
getEncryptedAlphabet(keyword.toLowerCase()),
message
)
} }
function decrypt (keyword, message) { function decrypt(keyword, message) {
checkInputs(keyword, message) checkInputs(keyword, message)
return translate(getEncryptedAlphabet(keyword.toLowerCase()), alphabet, message) return translate(
getEncryptedAlphabet(keyword.toLowerCase()),
alphabet,
message
)
} }
export { encrypt, decrypt } export { encrypt, decrypt }

View File

@ -50,7 +50,7 @@ const morse = (msg, dot = '*', dash = '-') => {
',': '--**--', ',': '--**--',
'?': '**--**', '?': '**--**',
'!': '-*-*--', '!': '-*-*--',
'\'': '*----*', "'": '*----*',
'"': '*-**-*', '"': '*-**-*',
'(': '-*--*', '(': '-*--*',
')': '-*--*-', ')': '-*--*-',
@ -68,9 +68,14 @@ const morse = (msg, dot = '*', dash = '-') => {
let newMsg = '' let newMsg = ''
msg.toString().split('').forEach((e) => { msg
.toString()
.split('')
.forEach((e) => {
if (/[a-zA-Z]/.test(e)) { if (/[a-zA-Z]/.test(e)) {
newMsg += key[e.toUpperCase()].replaceAll('*', dot).replaceAll('-', dash) newMsg += key[e.toUpperCase()]
.replaceAll('*', dot)
.replaceAll('-', dash)
} else if (Object.keys(key).includes(e)) { } else if (Object.keys(key).includes(e)) {
newMsg += key[e].replaceAll('*', dot).replaceAll('-', dash) newMsg += key[e].replaceAll('*', dot).replaceAll('-', dash)
} else { } else {

View File

@ -5,7 +5,7 @@
* @param {String} str - string to be decrypted * @param {String} str - string to be decrypted
* @return {String} decrypted string * @return {String} decrypted string
*/ */
function ROT13 (str) { function ROT13(str) {
if (typeof str !== 'string') { if (typeof str !== 'string') {
throw new TypeError('Argument should be string') throw new TypeError('Argument should be string')
} }

View File

@ -3,7 +3,7 @@
* @param {String} str - character to check * @param {String} str - character to check
* @return {object} An array with the character or null if isn't a letter * @return {object} An array with the character or null if isn't a letter
*/ */
function isLetter (str) { function isLetter(str) {
return str.length === 1 && str.match(/[a-zA-Z]/i) return str.length === 1 && str.match(/[a-zA-Z]/i)
} }
@ -12,7 +12,7 @@ function isLetter (str) {
* @param {String} character - character to check * @param {String} character - character to check
* @return {Boolean} result of the checking * @return {Boolean} result of the checking
*/ */
function isUpperCase (character) { function isUpperCase(character) {
if (character === character.toUpperCase()) { if (character === character.toUpperCase()) {
return true return true
} }
@ -27,16 +27,22 @@ function isUpperCase (character) {
* @param {String} key - key for encrypt * @param {String} key - key for encrypt
* @return {String} result - encrypted string * @return {String} result - encrypted string
*/ */
function encrypt (message, key) { function encrypt(message, key) {
let result = '' let result = ''
for (let i = 0, j = 0; i < message.length; i++) { for (let i = 0, j = 0; i < message.length; i++) {
const c = message.charAt(i) const c = message.charAt(i)
if (isLetter(c)) { if (isLetter(c)) {
if (isUpperCase(c)) { if (isUpperCase(c)) {
result += String.fromCharCode((c.charCodeAt(0) + key.toUpperCase().charCodeAt(j) - 2 * 65) % 26 + 65) // A: 65 result += String.fromCharCode(
((c.charCodeAt(0) + key.toUpperCase().charCodeAt(j) - 2 * 65) % 26) +
65
) // A: 65
} else { } else {
result += String.fromCharCode((c.charCodeAt(0) + key.toLowerCase().charCodeAt(j) - 2 * 97) % 26 + 97) // a: 97 result += String.fromCharCode(
((c.charCodeAt(0) + key.toLowerCase().charCodeAt(j) - 2 * 97) % 26) +
97
) // a: 97
} }
} else { } else {
result += c result += c
@ -52,16 +58,21 @@ function encrypt (message, key) {
* @param {String} key - key for decrypt * @param {String} key - key for decrypt
* @return {String} result - decrypted string * @return {String} result - decrypted string
*/ */
function decrypt (message, key) { function decrypt(message, key) {
let result = '' let result = ''
for (let i = 0, j = 0; i < message.length; i++) { for (let i = 0, j = 0; i < message.length; i++) {
const c = message.charAt(i) const c = message.charAt(i)
if (isLetter(c)) { if (isLetter(c)) {
if (isUpperCase(c)) { if (isUpperCase(c)) {
result += String.fromCharCode(90 - (25 - (c.charCodeAt(0) - key.toUpperCase().charCodeAt(j))) % 26) result += String.fromCharCode(
90 - ((25 - (c.charCodeAt(0) - key.toUpperCase().charCodeAt(j))) % 26)
)
} else { } else {
result += String.fromCharCode(122 - (25 - (c.charCodeAt(0) - key.toLowerCase().charCodeAt(j))) % 26) result += String.fromCharCode(
122 -
((25 - (c.charCodeAt(0) - key.toLowerCase().charCodeAt(j))) % 26)
)
} }
} else { } else {
result += c result += c

View File

@ -14,8 +14,8 @@ const XORCipher = (str, key) => {
throw new TypeError('Arguments type are invalid') throw new TypeError('Arguments type are invalid')
} }
return str.replace( return str.replace(/./g, (char) =>
/./g, (char) => String.fromCharCode(char.charCodeAt() ^ key) String.fromCharCode(char.charCodeAt() ^ key)
) )
} }

View File

@ -9,8 +9,14 @@ describe('Testing the caesarsCipher function', () => {
it('Test - 2, Testing for valid string and rotation', () => { it('Test - 2, Testing for valid string and rotation', () => {
expect(caesarCipher('middle-Outz', 2)).toBe('okffng-Qwvb') expect(caesarCipher('middle-Outz', 2)).toBe('okffng-Qwvb')
expect(caesarCipher('abcdefghijklmnopqrstuvwxyz', 3)).toBe('defghijklmnopqrstuvwxyzabc') expect(caesarCipher('abcdefghijklmnopqrstuvwxyz', 3)).toBe(
expect(caesarCipher('Always-Look-on-the-Bright-Side-of-Life', 5)).toBe('Fqbfdx-Qttp-ts-ymj-Gwnlmy-Xnij-tk-Qnkj') 'defghijklmnopqrstuvwxyzabc'
expect(caesarCipher('THE QUICK BROWN FOX JUMPS OVER THE LAZY DOG', 23)).toBe('QEB NRFZH YOLTK CLU GRJMP LSBO QEB IXWV ALD') )
expect(caesarCipher('Always-Look-on-the-Bright-Side-of-Life', 5)).toBe(
'Fqbfdx-Qttp-ts-ymj-Gwnlmy-Xnij-tk-Qnkj'
)
expect(
caesarCipher('THE QUICK BROWN FOX JUMPS OVER THE LAZY DOG', 23)
).toBe('QEB NRFZH YOLTK CLU GRJMP LSBO QEB IXWV ALD')
}) })
}) })

View File

@ -2,12 +2,16 @@ import { morse } from '../MorseCode'
describe('Testing morse function', () => { describe('Testing morse function', () => {
it('should return an enciphered string with a given input string', () => { it('should return an enciphered string with a given input string', () => {
expect(morse('Hello World!')).toBe('**** * *-** *-** --- *-- --- *-* *-** -** -*-*--') expect(morse('Hello World!')).toBe(
'**** * *-** *-** --- *-- --- *-* *-** -** -*-*--'
)
expect(morse('1+1=2')).toBe('*---- *-*-* *---- -***- **---') expect(morse('1+1=2')).toBe('*---- *-*-* *---- -***- **---')
}) })
it('should leave symbols that does not have its corresponding morse representation', () => { it('should leave symbols that does not have its corresponding morse representation', () => {
expect(morse('© 2023 GitHub, Inc.')).toBe('© **--- ----- **--- ***-- --* ** - **** **- -*** --**-- ** -* -*-* *-*-*-') expect(morse('© 2023 GitHub, Inc.')).toBe(
'© **--- ----- **--- ***-- --* ** - **** **- -*** --**-- ** -* -*-* *-*-*-'
)
}) })
it('should be able to accept custom morse code symbols', () => { it('should be able to accept custom morse code symbols', () => {

View File

@ -12,7 +12,11 @@ describe('Testing ROT13 function', () => {
it('Test - 2, passing a string as an argument', () => { it('Test - 2, passing a string as an argument', () => {
expect(ROT13('Uryyb Jbeyq')).toBe('Hello World') expect(ROT13('Uryyb Jbeyq')).toBe('Hello World')
expect(ROT13('ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz')).toBe('NOPQRSTUVWXYZABCDEFGHIJKLMnopqrstuvwxyzabcdefghijklm') expect(ROT13('ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz')).toBe(
expect(ROT13('The quick brown fox jumps over the lazy dog')).toBe('Gur dhvpx oebja sbk whzcf bire gur ynml qbt') 'NOPQRSTUVWXYZABCDEFGHIJKLMnopqrstuvwxyzabcdefghijklm'
)
expect(ROT13('The quick brown fox jumps over the lazy dog')).toBe(
'Gur dhvpx oebja sbk whzcf bire gur ynml qbt'
)
}) })
}) })

View File

@ -1,9 +1,9 @@
/** /**
* Divide two numbers and get the result of floor division and remainder * Divide two numbers and get the result of floor division and remainder
* @param {number} dividend * @param {number} dividend
* @param {number} divisor * @param {number} divisor
* @returns {[result: number, remainder: number]} * @returns {[result: number, remainder: number]}
*/ */
const floorDiv = (dividend, divisor) => { const floorDiv = (dividend, divisor) => {
const remainder = dividend % divisor const remainder = dividend % divisor
const result = Math.floor(dividend / divisor) const result = Math.floor(dividend / divisor)
@ -12,14 +12,22 @@ const floorDiv = (dividend, divisor) => {
} }
/** /**
* Converts a string from one base to other. Loses accuracy above the value of `Number.MAX_SAFE_INTEGER`. * Converts a string from one base to other. Loses accuracy above the value of `Number.MAX_SAFE_INTEGER`.
* @param {string} stringInBaseOne String in input base * @param {string} stringInBaseOne String in input base
* @param {string} baseOneCharacters Character set for the input base * @param {string} baseOneCharacters Character set for the input base
* @param {string} baseTwoCharacters Character set for the output base * @param {string} baseTwoCharacters Character set for the output base
* @returns {string} * @returns {string}
*/ */
const convertArbitraryBase = (stringInBaseOne, baseOneCharacterString, baseTwoCharacterString) => { const convertArbitraryBase = (
if ([stringInBaseOne, baseOneCharacterString, baseTwoCharacterString].map(arg => typeof arg).some(type => type !== 'string')) { stringInBaseOne,
baseOneCharacterString,
baseTwoCharacterString
) => {
if (
[stringInBaseOne, baseOneCharacterString, baseTwoCharacterString]
.map((arg) => typeof arg)
.some((type) => type !== 'string')
) {
throw new TypeError('Only string arguments are allowed') throw new TypeError('Only string arguments are allowed')
} }
@ -28,7 +36,9 @@ const convertArbitraryBase = (stringInBaseOne, baseOneCharacterString, baseTwoCh
for (const charactersInBase of [baseOneCharacters, baseTwoCharacters]) { for (const charactersInBase of [baseOneCharacters, baseTwoCharacters]) {
if (charactersInBase.length !== new Set(charactersInBase).size) { if (charactersInBase.length !== new Set(charactersInBase).size) {
throw new TypeError('Duplicate characters in character set are not allowed') throw new TypeError(
'Duplicate characters in character set are not allowed'
)
} }
} }
const reversedStringOneChars = [...stringInBaseOne].reverse() const reversedStringOneChars = [...stringInBaseOne].reverse()
@ -40,7 +50,7 @@ const convertArbitraryBase = (stringInBaseOne, baseOneCharacterString, baseTwoCh
if (digitNumber === -1) { if (digitNumber === -1) {
throw new TypeError(`Not a valid character: ${digit}`) throw new TypeError(`Not a valid character: ${digit}`)
} }
value += (digitNumber * placeValue) value += digitNumber * placeValue
placeValue *= stringOneBase placeValue *= stringOneBase
} }
const outputChars = [] const outputChars = []
@ -54,14 +64,22 @@ const convertArbitraryBase = (stringInBaseOne, baseOneCharacterString, baseTwoCh
} }
/** /**
* Converts a arbitrary-length string from one base to other. Doesn't lose accuracy. * Converts a arbitrary-length string from one base to other. Doesn't lose accuracy.
* @param {string} stringInBaseOne String in input base * @param {string} stringInBaseOne String in input base
* @param {string} baseOneCharacters Character set for the input base * @param {string} baseOneCharacters Character set for the input base
* @param {string} baseTwoCharacters Character set for the output base * @param {string} baseTwoCharacters Character set for the output base
* @returns {string} * @returns {string}
*/ */
const convertArbitraryBaseBigIntVersion = (stringInBaseOne, baseOneCharacterString, baseTwoCharacterString) => { const convertArbitraryBaseBigIntVersion = (
if ([stringInBaseOne, baseOneCharacterString, baseTwoCharacterString].map(arg => typeof arg).some(type => type !== 'string')) { stringInBaseOne,
baseOneCharacterString,
baseTwoCharacterString
) => {
if (
[stringInBaseOne, baseOneCharacterString, baseTwoCharacterString]
.map((arg) => typeof arg)
.some((type) => type !== 'string')
) {
throw new TypeError('Only string arguments are allowed') throw new TypeError('Only string arguments are allowed')
} }
@ -70,7 +88,9 @@ const convertArbitraryBaseBigIntVersion = (stringInBaseOne, baseOneCharacterStri
for (const charactersInBase of [baseOneCharacters, baseTwoCharacters]) { for (const charactersInBase of [baseOneCharacters, baseTwoCharacters]) {
if (charactersInBase.length !== new Set(charactersInBase).size) { if (charactersInBase.length !== new Set(charactersInBase).size) {
throw new TypeError('Duplicate characters in character set are not allowed') throw new TypeError(
'Duplicate characters in character set are not allowed'
)
} }
} }
const reversedStringOneChars = [...stringInBaseOne].reverse() const reversedStringOneChars = [...stringInBaseOne].reverse()
@ -82,7 +102,7 @@ const convertArbitraryBaseBigIntVersion = (stringInBaseOne, baseOneCharacterStri
if (digitNumber === -1n) { if (digitNumber === -1n) {
throw new TypeError(`Not a valid character: ${digit}`) throw new TypeError(`Not a valid character: ${digit}`)
} }
value += (digitNumber * placeValue) value += digitNumber * placeValue
placeValue *= stringOneBase placeValue *= stringOneBase
} }
const outputChars = [] const outputChars = []

View File

@ -5,9 +5,10 @@
* @param {ArrayBuffer} binaryData An ArrayBuffer which represents an array of bytes * @param {ArrayBuffer} binaryData An ArrayBuffer which represents an array of bytes
* @returns {string} A string containing the base64 encoding of `binaryData` * @returns {string} A string containing the base64 encoding of `binaryData`
*/ */
function bufferToBase64 (binaryData) { function bufferToBase64(binaryData) {
// The base64 encoding uses the following set of characters to encode any binary data as text // The base64 encoding uses the following set of characters to encode any binary data as text
const base64Table = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/' const base64Table =
'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'
// Every 3 bytes translates to 4 base64 characters, if we have less than 3 bytes we must append '=' chars as padding // Every 3 bytes translates to 4 base64 characters, if we have less than 3 bytes we must append '=' chars as padding
const padding = 3 - (binaryData.byteLength % 3) const padding = 3 - (binaryData.byteLength % 3)
// Create an instance of Uint8Array, to read from the binaryData array buffer // Create an instance of Uint8Array, to read from the binaryData array buffer
@ -31,7 +32,8 @@ function bufferToBase64 (binaryData) {
// Add padding '=' chars if needed // Add padding '=' chars if needed
if (padding !== 3) { if (padding !== 3) {
const paddedResult = result.slice(0, result.length - padding) + '='.repeat(padding) const paddedResult =
result.slice(0, result.length - padding) + '='.repeat(padding)
return paddedResult return paddedResult
} }

View File

@ -5,9 +5,10 @@
* @param {string} b64 A base64 string * @param {string} b64 A base64 string
* @returns {ArrayBuffer} An ArrayBuffer representing the bytes encoded by the base64 string * @returns {ArrayBuffer} An ArrayBuffer representing the bytes encoded by the base64 string
*/ */
function base64ToBuffer (b64) { function base64ToBuffer(b64) {
// The base64 encoding uses the following set of characters to encode any binary data as text // The base64 encoding uses the following set of characters to encode any binary data as text
const base64Table = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/' const base64Table =
'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'
// Find the index of char '=' first occurrence // Find the index of char '=' first occurrence
const paddingIdx = b64.indexOf('=') const paddingIdx = b64.indexOf('=')
// Remove padding chars from base64 string, if there are any // Remove padding chars from base64 string, if there are any

View File

@ -1,8 +1,8 @@
export default function binaryToDecimal (binaryString) { export default function binaryToDecimal(binaryString) {
let decimalNumber = 0 let decimalNumber = 0
const binaryDigits = binaryString.split('').reverse() // Splits the binary number into reversed single digits const binaryDigits = binaryString.split('').reverse() // Splits the binary number into reversed single digits
binaryDigits.forEach((binaryDigit, index) => { binaryDigits.forEach((binaryDigit, index) => {
decimalNumber += binaryDigit * (Math.pow(2, index)) // Summation of all the decimal converted digits decimalNumber += binaryDigit * Math.pow(2, index) // Summation of all the decimal converted digits
}) })
return decimalNumber return decimalNumber
} }

View File

@ -9,22 +9,38 @@ const hexLookup = (bin) => {
binary = pad(binary, 4) binary = pad(binary, 4)
} }
switch (binary) { switch (binary) {
case '0000': return '0' case '0000':
case '0001': return '1' return '0'
case '0010': return '2' case '0001':
case '0011': return '3' return '1'
case '0100': return '4' case '0010':
case '0101': return '5' return '2'
case '0110': return '6' case '0011':
case '0111': return '7' return '3'
case '1000': return '8' case '0100':
case '1001': return '9' return '4'
case '1010': return 'A' case '0101':
case '1011': return 'B' return '5'
case '1100': return 'C' case '0110':
case '1101': return 'D' return '6'
case '1110': return 'E' case '0111':
case '1111': return 'F' return '7'
case '1000':
return '8'
case '1001':
return '9'
case '1010':
return 'A'
case '1011':
return 'B'
case '1100':
return 'C'
case '1101':
return 'D'
case '1110':
return 'E'
case '1111':
return 'F'
} }
} }
const binaryToHex = (binaryString) => { const binaryToHex = (binaryString) => {

View File

@ -14,7 +14,15 @@ const isLeap = (year) => {
else return false else return false
} }
const DateToDay = (dd, mm, yyyy) => { const DateToDay = (dd, mm, yyyy) => {
return Math.floor((365 * (yyyy - 1)) + ((yyyy - 1) / 4) - ((yyyy - 1) / 100) + ((yyyy - 1) / 400) + dd + (((367 * mm) - 362) / 12) + (mm <= 2 ? 0 : isLeap(yyyy) ? -1 : -2)) return Math.floor(
365 * (yyyy - 1) +
(yyyy - 1) / 4 -
(yyyy - 1) / 100 +
(yyyy - 1) / 400 +
dd +
(367 * mm - 362) / 12 +
(mm <= 2 ? 0 : isLeap(yyyy) ? -1 : -2)
)
} }
const DateDayDifference = (date1, date2) => { const DateDayDifference = (date1, date2) => {
@ -23,17 +31,30 @@ const DateDayDifference = (date1, date2) => {
return new TypeError('Argument is not a string.') return new TypeError('Argument is not a string.')
} }
// extract the first date // extract the first date
const [firstDateDay, firstDateMonth, firstDateYear] = date1.split('/').map((ele) => Number(ele)) const [firstDateDay, firstDateMonth, firstDateYear] = date1
.split('/')
.map((ele) => Number(ele))
// extract the second date // extract the second date
const [secondDateDay, secondDateMonth, secondDateYear] = date2.split('/').map((ele) => Number(ele)) const [secondDateDay, secondDateMonth, secondDateYear] = date2
.split('/')
.map((ele) => Number(ele))
// check the both data are valid or not. // check the both data are valid or not.
if (firstDateDay < 0 || firstDateDay > 31 || if (
firstDateMonth > 12 || firstDateMonth < 0 || firstDateDay < 0 ||
secondDateDay < 0 || secondDateDay > 31 || firstDateDay > 31 ||
secondDateMonth > 12 || secondDateMonth < 0) { firstDateMonth > 12 ||
firstDateMonth < 0 ||
secondDateDay < 0 ||
secondDateDay > 31 ||
secondDateMonth > 12 ||
secondDateMonth < 0
) {
return new TypeError('Date is not valid.') return new TypeError('Date is not valid.')
} }
return Math.abs(DateToDay(secondDateDay, secondDateMonth, secondDateYear) - DateToDay(firstDateDay, firstDateMonth, firstDateYear)) return Math.abs(
DateToDay(secondDateDay, secondDateMonth, secondDateYear) -
DateToDay(firstDateDay, firstDateMonth, firstDateYear)
)
} }
// Example : DateDayDifference('17/08/2002', '10/10/2020') => 6630 // Example : DateDayDifference('17/08/2002', '10/10/2020') => 6630

View File

@ -13,7 +13,15 @@
*/ */
// Array holding name of the day: Saturday - Sunday - Friday => 0 - 1 - 6 // Array holding name of the day: Saturday - Sunday - Friday => 0 - 1 - 6
const daysNameArr = ['Saturday', 'Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday'] const daysNameArr = [
'Saturday',
'Sunday',
'Monday',
'Tuesday',
'Wednesday',
'Thursday',
'Friday'
]
const DateToDay = (date) => { const DateToDay = (date) => {
// firstly, check that input is a string or not. // firstly, check that input is a string or not.
@ -53,7 +61,14 @@ const DateToDay = (date) => {
Without the adaption, the formula yields `weekDay = -6` for the date 2/3/2014; Without the adaption, the formula yields `weekDay = -6` for the date 2/3/2014;
With the adaption, it yields the positive result `weekDay = 7 - 6 = 1` (Sunday), which is what we need to index the array With the adaption, it yields the positive result `weekDay = 7 - 6 = 1` (Sunday), which is what we need to index the array
*/ */
const weekDay = (day + Math.floor((month + 1) * 2.6) + yearDigits + Math.floor(yearDigits / 4) + Math.floor(century / 4) + 5 * century) % 7 const weekDay =
(day +
Math.floor((month + 1) * 2.6) +
yearDigits +
Math.floor(yearDigits / 4) +
Math.floor(century / 4) +
5 * century) %
7
return daysNameArr[weekDay] // name of the weekday return daysNameArr[weekDay] // name of the weekday
} }

View File

@ -1,4 +1,4 @@
function decimalToBinary (num) { function decimalToBinary(num) {
const bin = [] const bin = []
while (num > 0) { while (num > 0) {
bin.unshift(num % 2) bin.unshift(num % 2)

View File

@ -1,16 +1,22 @@
function intToHex (num) { function intToHex(num) {
switch (num) { switch (num) {
case 10: return 'A' case 10:
case 11: return 'B' return 'A'
case 12: return 'C' case 11:
case 13: return 'D' return 'B'
case 14: return 'E' case 12:
case 15: return 'F' return 'C'
case 13:
return 'D'
case 14:
return 'E'
case 15:
return 'F'
} }
return num return num
} }
function decimalToHex (num) { function decimalToHex(num) {
const hexOut = [] const hexOut = []
while (num > 15) { while (num > 15) {
hexOut.unshift(intToHex(num % 16)) hexOut.unshift(intToHex(num % 16))

View File

@ -1,9 +1,9 @@
function decimalToOctal (num) { function decimalToOctal(num) {
let oct = 0 let oct = 0
let c = 0 let c = 0
while (num > 0) { while (num > 0) {
const r = num % 8 const r = num % 8
oct = oct + (r * Math.pow(10, c++)) oct = oct + r * Math.pow(10, c++)
num = Math.floor(num / 8) // basically /= 8 without remainder if any num = Math.floor(num / 8) // basically /= 8 without remainder if any
} }
return oct return oct

View File

@ -38,7 +38,7 @@ const orders = [
'I' 'I'
] ]
function decimalToRoman (num) { function decimalToRoman(num) {
let roman = '' let roman = ''
for (const symbol of orders) { for (const symbol of orders) {
while (num >= values[symbol]) { while (num >= values[symbol]) {

View File

@ -1,4 +1,5 @@
const binLookup = (key) => ({ const binLookup = (key) =>
({
0: '0000', 0: '0000',
1: '0001', 1: '0001',
2: '0010', 2: '0010',
@ -15,7 +16,7 @@ const binLookup = (key) => ({
d: '1101', d: '1101',
e: '1110', e: '1110',
f: '1111' f: '1111'
}[key.toLowerCase()]) // select the binary number by valid hex key with the help javascript object })[key.toLowerCase()] // select the binary number by valid hex key with the help javascript object
const hexToBinary = (hexString) => { const hexToBinary = (hexString) => {
if (typeof hexString !== 'string') { if (typeof hexString !== 'string') {
@ -32,10 +33,7 @@ const hexToBinary = (hexString) => {
2. Conversion goes by searching in the lookup table 2. Conversion goes by searching in the lookup table
*/ */
return hexString.replace( return hexString.replace(/[0-9a-f]/gi, (lexeme) => binLookup(lexeme))
/[0-9a-f]/gi,
lexeme => binLookup(lexeme)
)
} }
export default hexToBinary export default hexToBinary

View File

@ -1,22 +1,31 @@
function hexToInt (hexNum) { function hexToInt(hexNum) {
const numArr = hexNum.split('') // converts number to array const numArr = hexNum.split('') // converts number to array
return numArr.map((item, index) => { return numArr.map((item, index) => {
switch (item) { switch (item) {
case 'A': return 10 case 'A':
case 'B': return 11 return 10
case 'C': return 12 case 'B':
case 'D': return 13 return 11
case 'E': return 14 case 'C':
case 'F': return 15 return 12
default: return parseInt(item) case 'D':
return 13
case 'E':
return 14
case 'F':
return 15
default:
return parseInt(item)
} }
}) })
} }
function hexToDecimal (hexNum) { function hexToDecimal(hexNum) {
const intItemsArr = hexToInt(hexNum) const intItemsArr = hexToInt(hexNum)
return intItemsArr.reduce((accumulator, current, index) => { return intItemsArr.reduce((accumulator, current, index) => {
return accumulator + (current * Math.pow(16, (intItemsArr.length - (1 + index)))) return (
accumulator + current * Math.pow(16, intItemsArr.length - (1 + index))
)
}, 0) }, 0)
} }

View File

@ -1,4 +1,4 @@
function hexStringToRGB (hexString) { function hexStringToRGB(hexString) {
let r = hexString.substring(0, 2) let r = hexString.substring(0, 2)
let g = hexString.substring(2, 4) let g = hexString.substring(2, 4)
let b = hexString.substring(4, 6) let b = hexString.substring(4, 6)

View File

@ -33,6 +33,4 @@ const lengthConversion = (length, fromUnit, toUnit) => {
return convertedLength return convertedLength
} }
export { export { lengthConversion }
lengthConversion
}

View File

@ -17,7 +17,7 @@
*/ */
const LowerCaseConversion = (inputString) => { const LowerCaseConversion = (inputString) => {
// Take a string and split it into characters. // Take a string and split it into characters.
const newString = inputString.split('').map(char => { const newString = inputString.split('').map((char) => {
// Get a character code by the use charCodeAt method. // Get a character code by the use charCodeAt method.
const presentCharCode = char.charCodeAt() const presentCharCode = char.charCodeAt()
// If the character code lies between 65 to 90 it means they are in the upper case so convert it. // If the character code lies between 65 to 90 it means they are in the upper case so convert it.

View File

@ -1,10 +1,10 @@
function octalToDecimal (num) { function octalToDecimal(num) {
let dec = 0 let dec = 0
let base = 1 let base = 1
while (num > 0) { while (num > 0) {
const r = num % 10 const r = num % 10
num = Math.floor(num / 10) num = Math.floor(num / 10)
dec = dec + (r * base) dec = dec + r * base
base = base * 8 base = base * 8
} }
return dec return dec

View File

@ -5,7 +5,7 @@
* @param {number} oz - Amount of ounces to convert to kilograms * @param {number} oz - Amount of ounces to convert to kilograms
*/ */
const ouncesToKilograms = (oz) => { const ouncesToKilograms = (oz) => {
return oz * 28.3498 / 1000 return (oz * 28.3498) / 1000
} }
export default ouncesToKilograms export default ouncesToKilograms

View File

@ -1,13 +1,9 @@
function RGBToHex (r, g, b) { function RGBToHex(r, g, b) {
if ( if (typeof r !== 'number' || typeof g !== 'number' || typeof b !== 'number') {
typeof r !== 'number' ||
typeof g !== 'number' ||
typeof b !== 'number'
) {
throw new TypeError('argument is not a Number') throw new TypeError('argument is not a Number')
} }
const toHex = n => (n || '0').toString(16).padStart(2, '0') const toHex = (n) => (n || '0').toString(16).padStart(2, '0')
return `#${toHex(r)}${toHex(g)}${toHex(b)}` return `#${toHex(r)}${toHex(g)}${toHex(b)}`
} }

View File

@ -23,12 +23,23 @@ const RailwayTimeConversion = (timeString) => {
// split the string by ':' character. // split the string by ':' character.
const [hour, minute, secondWithShift] = timeString.split(':') const [hour, minute, secondWithShift] = timeString.split(':')
// split second and shift value. // split second and shift value.
const [second, shift] = [secondWithShift.substr(0, 2), secondWithShift.substr(2)] const [second, shift] = [
secondWithShift.substr(0, 2),
secondWithShift.substr(2)
]
// convert shifted time to not-shift time(Railway time) by using the above explanation. // convert shifted time to not-shift time(Railway time) by using the above explanation.
if (shift === 'PM') { if (shift === 'PM') {
if (parseInt(hour) === 12) { return `${hour}:${minute}:${second}` } else { return `${parseInt(hour) + 12}:${minute}:${second}` } if (parseInt(hour) === 12) {
return `${hour}:${minute}:${second}`
} else { } else {
if (parseInt(hour) === 12) { return `00:${minute}:${second}` } else { return `${hour}:${minute}:${second}` } return `${parseInt(hour) + 12}:${minute}:${second}`
}
} else {
if (parseInt(hour) === 12) {
return `00:${minute}:${second}`
} else {
return `${hour}:${minute}:${second}`
}
} }
} }

View File

@ -16,7 +16,7 @@
* @param value Brightness-value of the color. * @param value Brightness-value of the color.
* @return The tuple of RGB-components. * @return The tuple of RGB-components.
*/ */
export function hsvToRgb (hue, saturation, value) { export function hsvToRgb(hue, saturation, value) {
if (hue < 0 || hue > 360) { if (hue < 0 || hue > 360) {
throw new Error('hue should be between 0 and 360') throw new Error('hue should be between 0 and 360')
} }
@ -31,7 +31,7 @@ export function hsvToRgb (hue, saturation, value) {
const chroma = value * saturation const chroma = value * saturation
const hueSection = hue / 60 const hueSection = hue / 60
const secondLargestComponent = chroma * (1 - Math.abs(hueSection % 2 - 1)) const secondLargestComponent = chroma * (1 - Math.abs((hueSection % 2) - 1))
const matchValue = value - chroma const matchValue = value - chroma
return getRgbBySection(hueSection, chroma, matchValue, secondLargestComponent) return getRgbBySection(hueSection, chroma, matchValue, secondLargestComponent)
@ -45,7 +45,7 @@ export function hsvToRgb (hue, saturation, value) {
* @param blue Blue-component of the color. * @param blue Blue-component of the color.
* @return The tuple of HSV-components. * @return The tuple of HSV-components.
*/ */
export function rgbToHsv (red, green, blue) { export function rgbToHsv(red, green, blue) {
if (red < 0 || red > 255) { if (red < 0 || red > 255) {
throw new Error('red should be between 0 and 255') throw new Error('red should be between 0 and 255')
} }
@ -81,7 +81,7 @@ export function rgbToHsv (red, green, blue) {
return [hue, saturation, value] return [hue, saturation, value]
} }
export function approximatelyEqualHsv (hsv1, hsv2) { export function approximatelyEqualHsv(hsv1, hsv2) {
const bHue = Math.abs(hsv1[0] - hsv2[0]) < 0.2 const bHue = Math.abs(hsv1[0] - hsv2[0]) < 0.2
const bSaturation = Math.abs(hsv1[1] - hsv2[1]) < 0.002 const bSaturation = Math.abs(hsv1[1] - hsv2[1]) < 0.002
const bValue = Math.abs(hsv1[2] - hsv2[2]) < 0.002 const bValue = Math.abs(hsv1[2] - hsv2[2]) < 0.002
@ -89,8 +89,13 @@ export function approximatelyEqualHsv (hsv1, hsv2) {
return bHue && bSaturation && bValue return bHue && bSaturation && bValue
} }
function getRgbBySection (hueSection, chroma, matchValue, secondLargestComponent) { function getRgbBySection(
function convertToInt (input) { hueSection,
chroma,
matchValue,
secondLargestComponent
) {
function convertToInt(input) {
return Math.round(255 * input) return Math.round(255 * input)
} }

View File

@ -8,7 +8,7 @@ const values = {
M: 1000 M: 1000
} }
export function romanToDecimal (romanNumber) { export function romanToDecimal(romanNumber) {
let prev = ' ' let prev = ' '
let sum = 0 let sum = 0

View File

@ -4,99 +4,110 @@
const celsiusToFahrenheit = (celsius) => { const celsiusToFahrenheit = (celsius) => {
// Wikipedia reference: https://en.wikipedia.org/wiki/Celsius // Wikipedia reference: https://en.wikipedia.org/wiki/Celsius
// Wikipedia reference: https://en.wikipedia.org/wiki/Fahrenheit // Wikipedia reference: https://en.wikipedia.org/wiki/Fahrenheit
return Math.round(((celsius) * 9 / 5) + 32) return Math.round((celsius * 9) / 5 + 32)
} }
const celsiusToKelvin = (celsius) => { const celsiusToKelvin = (celsius) => {
// Wikipedia reference: https://en.wikipedia.org/wiki/Celsius // Wikipedia reference: https://en.wikipedia.org/wiki/Celsius
// Wikipedia reference: https://en.wikipedia.org/wiki/Kelvin // Wikipedia reference: https://en.wikipedia.org/wiki/Kelvin
return Math.round((celsius) + 273.15) return Math.round(celsius + 273.15)
} }
const celsiusToRankine = (celsius) => { const celsiusToRankine = (celsius) => {
// Wikipedia reference: https://en.wikipedia.org/wiki/Celsius // Wikipedia reference: https://en.wikipedia.org/wiki/Celsius
// Wikipedia reference: https://en.wikipedia.org/wiki/Rankine_scale // Wikipedia reference: https://en.wikipedia.org/wiki/Rankine_scale
return Math.round(((celsius) * 9 / 5) + 491.67) return Math.round((celsius * 9) / 5 + 491.67)
} }
const fahrenheitToCelsius = (fahrenheit) => { const fahrenheitToCelsius = (fahrenheit) => {
// Wikipedia reference: https://en.wikipedia.org/wiki/Fahrenheit // Wikipedia reference: https://en.wikipedia.org/wiki/Fahrenheit
// Wikipedia reference: https://en.wikipedia.org/wiki/Celsius // Wikipedia reference: https://en.wikipedia.org/wiki/Celsius
return Math.round(((fahrenheit) - 32) * 5 / 9) return Math.round(((fahrenheit - 32) * 5) / 9)
} }
const fahrenheitToKelvin = (fahrenheit) => { const fahrenheitToKelvin = (fahrenheit) => {
// Wikipedia reference: https://en.wikipedia.org/wiki/Fahrenheit // Wikipedia reference: https://en.wikipedia.org/wiki/Fahrenheit
// Wikipedia reference: https://en.wikipedia.org/wiki/Kelvin // Wikipedia reference: https://en.wikipedia.org/wiki/Kelvin
return Math.round((((fahrenheit) - 32) * 5 / 9) + 273.15) return Math.round(((fahrenheit - 32) * 5) / 9 + 273.15)
} }
const fahrenheitToRankine = (fahrenheit) => { const fahrenheitToRankine = (fahrenheit) => {
// Wikipedia reference: https://en.wikipedia.org/wiki/Fahrenheit // Wikipedia reference: https://en.wikipedia.org/wiki/Fahrenheit
// Wikipedia reference: https://en.wikipedia.org/wiki/Rankine_scale // Wikipedia reference: https://en.wikipedia.org/wiki/Rankine_scale
return Math.round((fahrenheit) + 459.67) return Math.round(fahrenheit + 459.67)
} }
const kelvinToCelsius = (kelvin) => { const kelvinToCelsius = (kelvin) => {
// Wikipedia reference: https://en.wikipedia.org/wiki/Kelvin // Wikipedia reference: https://en.wikipedia.org/wiki/Kelvin
// Wikipedia reference: https://en.wikipedia.org/wiki/Celsius // Wikipedia reference: https://en.wikipedia.org/wiki/Celsius
return Math.round((kelvin) - 273.15) return Math.round(kelvin - 273.15)
} }
const kelvinToFahrenheit = (kelvin) => { const kelvinToFahrenheit = (kelvin) => {
// Wikipedia reference: https://en.wikipedia.org/wiki/Kelvin // Wikipedia reference: https://en.wikipedia.org/wiki/Kelvin
// Wikipedia reference: https://en.wikipedia.org/wiki/Fahrenheit // Wikipedia reference: https://en.wikipedia.org/wiki/Fahrenheit
return Math.round((((kelvin) - 273.15) * 9 / 5) + 32) return Math.round(((kelvin - 273.15) * 9) / 5 + 32)
} }
const kelvinToRankine = (kelvin) => { const kelvinToRankine = (kelvin) => {
// Wikipedia reference: https://en.wikipedia.org/wiki/Kelvin // Wikipedia reference: https://en.wikipedia.org/wiki/Kelvin
// Wikipedia reference: https://en.wikipedia.org/wiki/Rankine_scale // Wikipedia reference: https://en.wikipedia.org/wiki/Rankine_scale
return Math.round(((kelvin) * 9 / 5)) return Math.round((kelvin * 9) / 5)
} }
const rankineToCelsius = (rankine) => { const rankineToCelsius = (rankine) => {
// Wikipedia reference: https://en.wikipedia.org/wiki/Rankine_scale // Wikipedia reference: https://en.wikipedia.org/wiki/Rankine_scale
// Wikipedia reference: https://en.wikipedia.org/wiki/Celsius // Wikipedia reference: https://en.wikipedia.org/wiki/Celsius
return Math.round(((rankine) - 491.67) * 5 / 9) return Math.round(((rankine - 491.67) * 5) / 9)
} }
const rankineToFahrenheit = (rankine) => { const rankineToFahrenheit = (rankine) => {
// Wikipedia reference: https://en.wikipedia.org/wiki/Rankine_scale // Wikipedia reference: https://en.wikipedia.org/wiki/Rankine_scale
// Wikipedia reference: https://en.wikipedia.org/wiki/Fahrenheit // Wikipedia reference: https://en.wikipedia.org/wiki/Fahrenheit
return Math.round((rankine) - 459.67) return Math.round(rankine - 459.67)
} }
const rankineToKelvin = (rankine) => { const rankineToKelvin = (rankine) => {
// Wikipedia reference: https://en.wikipedia.org/wiki/Rankine_scale // Wikipedia reference: https://en.wikipedia.org/wiki/Rankine_scale
// Wikipedia reference: https://en.wikipedia.org/wiki/Kelvin // Wikipedia reference: https://en.wikipedia.org/wiki/Kelvin
return Math.round(((rankine) * 5 / 9)) return Math.round((rankine * 5) / 9)
} }
const reaumurToKelvin = (reaumur) => { const reaumurToKelvin = (reaumur) => {
// Reference:- http://www.csgnetwork.com/temp2conv.html // Reference:- http://www.csgnetwork.com/temp2conv.html
return Math.round(((reaumur) * 1.25 + 273.15)) return Math.round(reaumur * 1.25 + 273.15)
} }
const reaumurToFahrenheit = (reaumur) => { const reaumurToFahrenheit = (reaumur) => {
// Reference:- http://www.csgnetwork.com/temp2conv.html // Reference:- http://www.csgnetwork.com/temp2conv.html
return Math.round(((reaumur) * 2.25 + 32)) return Math.round(reaumur * 2.25 + 32)
} }
const reaumurToCelsius = (reaumur) => { const reaumurToCelsius = (reaumur) => {
// Reference:- http://www.csgnetwork.com/temp2conv.html // Reference:- http://www.csgnetwork.com/temp2conv.html
return Math.round(((reaumur) * 1.25)) return Math.round(reaumur * 1.25)
} }
const reaumurToRankine = (reaumur) => { const reaumurToRankine = (reaumur) => {
// Reference:- http://www.csgnetwork.com/temp2conv.html // Reference:- http://www.csgnetwork.com/temp2conv.html
return Math.round(((reaumur) * 2.25 + 32 + 459.67)) return Math.round(reaumur * 2.25 + 32 + 459.67)
} }
export { export {
celsiusToFahrenheit, celsiusToKelvin, celsiusToRankine, celsiusToFahrenheit,
fahrenheitToCelsius, fahrenheitToKelvin, fahrenheitToRankine, celsiusToKelvin,
kelvinToCelsius, kelvinToFahrenheit, kelvinToRankine, celsiusToRankine,
rankineToCelsius, rankineToFahrenheit, rankineToKelvin, fahrenheitToCelsius,
reaumurToCelsius, reaumurToFahrenheit, reaumurToKelvin, reaumurToRankine fahrenheitToKelvin,
fahrenheitToRankine,
kelvinToCelsius,
kelvinToFahrenheit,
kelvinToRankine,
rankineToCelsius,
rankineToFahrenheit,
rankineToKelvin,
reaumurToCelsius,
reaumurToFahrenheit,
reaumurToKelvin,
reaumurToRankine
} }

View File

@ -13,7 +13,7 @@
const titleCaseConversion = (inputString) => { const titleCaseConversion = (inputString) => {
if (inputString === '') return '' if (inputString === '') return ''
// Extract all space separated string. // Extract all space separated string.
const stringCollections = inputString.split(' ').map(word => { const stringCollections = inputString.split(' ').map((word) => {
let firstChar = '' let firstChar = ''
// Get the [ASCII](https://en.wikipedia.org/wiki/ASCII) character code by the use charCodeAt method. // Get the [ASCII](https://en.wikipedia.org/wiki/ASCII) character code by the use charCodeAt method.
const firstCharCode = word[0].charCodeAt() const firstCharCode = word[0].charCodeAt()
@ -25,7 +25,10 @@ const titleCaseConversion = (inputString) => {
// Else store the characters without any modification. // Else store the characters without any modification.
firstChar += word[0] firstChar += word[0]
} }
const newWordChar = word.slice(1).split('').map(char => { const newWordChar = word
.slice(1)
.split('')
.map((char) => {
// Get the ASCII character code by the use charCodeAt method. // Get the ASCII character code by the use charCodeAt method.
const presentCharCode = char.charCodeAt() const presentCharCode = char.charCodeAt()
// If the ASCII character code lies between 65 to 90, it means they are in the uppercase so convert it. // If the ASCII character code lies between 65 to 90, it means they are in the uppercase so convert it.

View File

@ -17,7 +17,7 @@
*/ */
const upperCaseConversion = (inputString) => { const upperCaseConversion = (inputString) => {
// Take a string and split it into characters. // Take a string and split it into characters.
const newString = inputString.split('').map(char => { const newString = inputString.split('').map((char) => {
// Get a character code by the use charCodeAt method. // Get a character code by the use charCodeAt method.
const presentCharCode = char.charCodeAt() const presentCharCode = char.charCodeAt()
// If the character code lies between 97 to 122, it means they are in the lowercase so convert it. // If the character code lies between 97 to 122, it means they are in the lowercase so convert it.

View File

@ -1,4 +1,7 @@
import { convertArbitraryBase, convertArbitraryBaseBigIntVersion } from '../ArbitraryBase' import {
convertArbitraryBase,
convertArbitraryBaseBigIntVersion
} from '../ArbitraryBase'
test('Check the answer of convertArbitraryBase(98, 0123456789, 01234567) is 142', () => { test('Check the answer of convertArbitraryBase(98, 0123456789, 01234567) is 142', () => {
const res = convertArbitraryBase('98', '0123456789', '01234567') const res = convertArbitraryBase('98', '0123456789', '01234567')

View File

@ -14,6 +14,8 @@ describe('BinaryToHex', () => {
}) })
it('expects to return correct hexadecimal value, matching (num).toString(16)', () => { it('expects to return correct hexadecimal value, matching (num).toString(16)', () => {
expect(binaryToHex('1111')).toBe(parseInt('1111', 2).toString(16).toUpperCase()) expect(binaryToHex('1111')).toBe(
parseInt('1111', 2).toString(16).toUpperCase()
)
}) })
}) })

View File

@ -6,7 +6,7 @@ describe('LengthConversion', () => {
${10} | ${'km'} | ${'m'} | ${10000} ${10} | ${'km'} | ${'m'} | ${10000}
${100} | ${'m'} | ${'km'} | ${0.1} ${100} | ${'m'} | ${'km'} | ${0.1}
${5} | ${'cm'} | ${'mm'} | ${50} ${5} | ${'cm'} | ${'mm'} | ${50}
${12} | ${'ft'} | ${'inch'}| ${144.00000000000003} ${12} | ${'ft'} | ${'inch'} | ${144.00000000000003}
`( `(
'converts $length $fromUnit to $toUnit', 'converts $length $fromUnit to $toUnit',
({ length, fromUnit, toUnit, expected }) => { ({ length, fromUnit, toUnit, expected }) => {
@ -22,8 +22,8 @@ describe('LengthConversion', () => {
it.each` it.each`
length | fromUnit | toUnit | expected length | fromUnit | toUnit | expected
${10} | ${'m'} | ${'km'} | ${0.01} ${10} | ${'m'} | ${'km'} | ${0.01}
${1000}| ${'mm'} | ${'cm'} | ${100} ${1000} | ${'mm'} | ${'cm'} | ${100}
${1} | ${'inch'}| ${'ft'} | ${0.08333333333} ${1} | ${'inch'} | ${'ft'} | ${0.08333333333}
`( `(
'converts $length $fromUnit to $toUnit (vice versa)', 'converts $length $fromUnit to $toUnit (vice versa)',
({ length, fromUnit, toUnit, expected }) => { ({ length, fromUnit, toUnit, expected }) => {

View File

@ -20,14 +20,30 @@ describe('rgbToHsv', () => {
// "approximatelyEqualHsv" needed because of small deviations due to rounding for the RGB-values // "approximatelyEqualHsv" needed because of small deviations due to rounding for the RGB-values
it('should calculate the correct HSV values', () => { it('should calculate the correct HSV values', () => {
expect(approximatelyEqualHsv(rgbToHsv(0, 0, 0), [0, 0, 0])).toEqual(true) expect(approximatelyEqualHsv(rgbToHsv(0, 0, 0), [0, 0, 0])).toEqual(true)
expect(approximatelyEqualHsv(rgbToHsv(255, 255, 255), [0, 0, 1])).toEqual(true) expect(approximatelyEqualHsv(rgbToHsv(255, 255, 255), [0, 0, 1])).toEqual(
true
)
expect(approximatelyEqualHsv(rgbToHsv(255, 0, 0), [0, 1, 1])).toEqual(true) expect(approximatelyEqualHsv(rgbToHsv(255, 0, 0), [0, 1, 1])).toEqual(true)
expect(approximatelyEqualHsv(rgbToHsv(255, 255, 0), [60, 1, 1])).toEqual(true) expect(approximatelyEqualHsv(rgbToHsv(255, 255, 0), [60, 1, 1])).toEqual(
expect(approximatelyEqualHsv(rgbToHsv(0, 255, 0), [120, 1, 1])).toEqual(true) true
expect(approximatelyEqualHsv(rgbToHsv(0, 0, 255), [240, 1, 1])).toEqual(true) )
expect(approximatelyEqualHsv(rgbToHsv(255, 0, 255), [300, 1, 1])).toEqual(true) expect(approximatelyEqualHsv(rgbToHsv(0, 255, 0), [120, 1, 1])).toEqual(
expect(approximatelyEqualHsv(rgbToHsv(64, 128, 128), [180, 0.5, 0.5])).toEqual(true) true
expect(approximatelyEqualHsv(rgbToHsv(193, 196, 224), [234, 0.14, 0.88])).toEqual(true) )
expect(approximatelyEqualHsv(rgbToHsv(128, 32, 80), [330, 0.75, 0.5])).toEqual(true) expect(approximatelyEqualHsv(rgbToHsv(0, 0, 255), [240, 1, 1])).toEqual(
true
)
expect(approximatelyEqualHsv(rgbToHsv(255, 0, 255), [300, 1, 1])).toEqual(
true
)
expect(
approximatelyEqualHsv(rgbToHsv(64, 128, 128), [180, 0.5, 0.5])
).toEqual(true)
expect(
approximatelyEqualHsv(rgbToHsv(193, 196, 224), [234, 0.14, 0.88])
).toEqual(true)
expect(
approximatelyEqualHsv(rgbToHsv(128, 32, 80), [330, 0.75, 0.5])
).toEqual(true)
}) })
}) })

View File

@ -1,12 +1,14 @@
import { titleCaseConversion } from '../TitleCaseConversion' import { titleCaseConversion } from '../TitleCaseConversion'
describe(('Tests for the titleCaseConversion function'), () => { describe('Tests for the titleCaseConversion function', () => {
it('should return an empty string when the input is an empty string', () => { it('should return an empty string when the input is an empty string', () => {
expect(titleCaseConversion('')).toEqual('') expect(titleCaseConversion('')).toEqual('')
}) })
it('should return the input string when the input string is a title case string', () => { it('should return the input string when the input string is a title case string', () => {
expect(titleCaseConversion('A Proper Title Case String')).toEqual('A Proper Title Case String') expect(titleCaseConversion('A Proper Title Case String')).toEqual(
'A Proper Title Case String'
)
}) })
it('should return a title case string when input is an all-uppercase string', () => { it('should return a title case string when input is an all-uppercase string', () => {
@ -34,7 +36,9 @@ describe(('Tests for the titleCaseConversion function'), () => {
}) })
it('should return a title case string when input is an all-lowercase string with punctuation', () => { it('should return a title case string when input is an all-lowercase string with punctuation', () => {
expect(titleCaseConversion('lower, case, input.')).toEqual('Lower, Case, Input.') expect(titleCaseConversion('lower, case, input.')).toEqual(
'Lower, Case, Input.'
)
}) })
it('should return a title case string when input is an mixed-case string', () => { it('should return a title case string when input is an mixed-case string', () => {
@ -46,6 +50,8 @@ describe(('Tests for the titleCaseConversion function'), () => {
}) })
it('should return a title case string when input is an mixed-case string with punctuation', () => { it('should return a title case string when input is an mixed-case string with punctuation', () => {
expect(titleCaseConversion('mixeD, CaSe, INPuT!')).toEqual('Mixed, Case, Input!') expect(titleCaseConversion('mixeD, CaSe, INPuT!')).toEqual(
'Mixed, Case, Input!'
)
}) })
}) })

View File

@ -1,6 +1,6 @@
import { upperCaseConversion } from '../UpperCaseConversion' import { upperCaseConversion } from '../UpperCaseConversion'
describe(('Test the upperCaseConversion function'), () => { describe('Test the upperCaseConversion function', () => {
it('should return an empty string when the input is an empty string', () => { it('should return an empty string when the input is an empty string', () => {
expect(upperCaseConversion('')).toEqual('') expect(upperCaseConversion('')).toEqual('')
}) })
@ -26,7 +26,9 @@ describe(('Test the upperCaseConversion function'), () => {
}) })
it('should return an all-uppercase string when input is an all-lowercase string with punctuation', () => { it('should return an all-uppercase string when input is an all-lowercase string with punctuation', () => {
expect(upperCaseConversion('lower-case, input.')).toEqual('LOWER-CASE, INPUT.') expect(upperCaseConversion('lower-case, input.')).toEqual(
'LOWER-CASE, INPUT.'
)
}) })
it('should return an all-uppercase string when input is an mixed-case string', () => { it('should return an all-uppercase string when input is an mixed-case string', () => {
@ -38,6 +40,8 @@ describe(('Test the upperCaseConversion function'), () => {
}) })
it('should return an all-uppercase string when input is an mixed-case string with punctuation', () => { it('should return an all-uppercase string when input is an mixed-case string with punctuation', () => {
expect(upperCaseConversion('mixeD-CaSe INPuT!')).toEqual('MIXED-CASE INPUT!') expect(upperCaseConversion('mixeD-CaSe INPuT!')).toEqual(
'MIXED-CASE INPUT!'
)
}) })
}) })

View File

@ -47,6 +47,7 @@
* [HexToBinary](Conversions/HexToBinary.js) * [HexToBinary](Conversions/HexToBinary.js)
* [HexToDecimal](Conversions/HexToDecimal.js) * [HexToDecimal](Conversions/HexToDecimal.js)
* [HexToRGB](Conversions/HexToRGB.js) * [HexToRGB](Conversions/HexToRGB.js)
* [LengthConversion](Conversions/LengthConversion.js)
* [LitersToImperialGallons](Conversions/LitersToImperialGallons.js) * [LitersToImperialGallons](Conversions/LitersToImperialGallons.js)
* [LitersToUSGallons](Conversions/LitersToUSGallons.js) * [LitersToUSGallons](Conversions/LitersToUSGallons.js)
* [LowerCaseConversion](Conversions/LowerCaseConversion.js) * [LowerCaseConversion](Conversions/LowerCaseConversion.js)
@ -233,6 +234,7 @@
* [PowLogarithmic](Maths/PowLogarithmic.js) * [PowLogarithmic](Maths/PowLogarithmic.js)
* [PrimeCheck](Maths/PrimeCheck.js) * [PrimeCheck](Maths/PrimeCheck.js)
* [PrimeFactors](Maths/PrimeFactors.js) * [PrimeFactors](Maths/PrimeFactors.js)
* [QuadraticRoots](Maths/QuadraticRoots.js)
* [RadianToDegree](Maths/RadianToDegree.js) * [RadianToDegree](Maths/RadianToDegree.js)
* [ReverseNumber](Maths/ReverseNumber.js) * [ReverseNumber](Maths/ReverseNumber.js)
* [ReversePolishNotation](Maths/ReversePolishNotation.js) * [ReversePolishNotation](Maths/ReversePolishNotation.js)
@ -363,6 +365,7 @@
* [HammingDistance](String/HammingDistance.js) * [HammingDistance](String/HammingDistance.js)
* [IsPalindrome](String/IsPalindrome.js) * [IsPalindrome](String/IsPalindrome.js)
* [KMPPatternSearching](String/KMPPatternSearching.js) * [KMPPatternSearching](String/KMPPatternSearching.js)
* [LengthofLongestSubstringWithoutRepetition](String/LengthofLongestSubstringWithoutRepetition.js)
* [LevenshteinDistance](String/LevenshteinDistance.js) * [LevenshteinDistance](String/LevenshteinDistance.js)
* [Lower](String/Lower.js) * [Lower](String/Lower.js)
* [MaxCharacter](String/MaxCharacter.js) * [MaxCharacter](String/MaxCharacter.js)

View File

@ -9,19 +9,38 @@
* @complexity: O(log(n)) (worst case) * @complexity: O(log(n)) (worst case)
* @flow * @flow
*/ */
const findMaxPointIndex = (array, rangeStartIndex, rangeEndIndex, originalLength) => { const findMaxPointIndex = (
array,
rangeStartIndex,
rangeEndIndex,
originalLength
) => {
// find index range middle point // find index range middle point
const middleIndex = rangeStartIndex + parseInt((rangeEndIndex - rangeStartIndex) / 2) const middleIndex =
rangeStartIndex + parseInt((rangeEndIndex - rangeStartIndex) / 2)
// handle array bounds // handle array bounds
if ((middleIndex === 0 || array[middleIndex - 1] <= array[middleIndex]) && if (
(middleIndex === originalLength - 1 || array[middleIndex + 1] <= array[middleIndex])) { (middleIndex === 0 || array[middleIndex - 1] <= array[middleIndex]) &&
(middleIndex === originalLength - 1 ||
array[middleIndex + 1] <= array[middleIndex])
) {
return middleIndex return middleIndex
} else if (middleIndex > 0 && array[middleIndex - 1] > array[middleIndex]) { } else if (middleIndex > 0 && array[middleIndex - 1] > array[middleIndex]) {
return findMaxPointIndex(array, rangeStartIndex, (middleIndex - 1), originalLength) return findMaxPointIndex(
array,
rangeStartIndex,
middleIndex - 1,
originalLength
)
} else { } else {
// regular local max // regular local max
return findMaxPointIndex(array, (middleIndex + 1), rangeEndIndex, originalLength) return findMaxPointIndex(
array,
middleIndex + 1,
rangeEndIndex,
originalLength
)
} }
} }

View File

@ -33,10 +33,13 @@ const CountLocalMaximumPoints = (array, startIndex, endIndex) => {
// handle the two halves // handle the two halves
const middleIndex = parseInt((startIndex + endIndex) / 2) const middleIndex = parseInt((startIndex + endIndex) / 2)
return CountLocalMaximumPoints(array, startIndex, middleIndex) + return (
CountLocalMaximumPoints(array, startIndex, middleIndex) +
CountLocalMaximumPoints(array, middleIndex + 1, endIndex) CountLocalMaximumPoints(array, middleIndex + 1, endIndex)
)
} }
const NumberOfLocalMaximumPoints = (A) => CountLocalMaximumPoints(A, 0, A.length - 1) const NumberOfLocalMaximumPoints = (A) =>
CountLocalMaximumPoints(A, 0, A.length - 1)
export { NumberOfLocalMaximumPoints } export { NumberOfLocalMaximumPoints }

View File

@ -11,7 +11,8 @@
* @flow * @flow
*/ */
function QuickSelect (items, kth) { // eslint-disable-line no-unused-vars function QuickSelect(items, kth) {
// eslint-disable-line no-unused-vars
if (kth < 1 || kth > items.length) { if (kth < 1 || kth > items.length) {
throw new RangeError('Index Out of Bound') throw new RangeError('Index Out of Bound')
} }
@ -19,7 +20,7 @@ function QuickSelect (items, kth) { // eslint-disable-line no-unused-vars
return RandomizedSelect(items, 0, items.length - 1, kth) return RandomizedSelect(items, 0, items.length - 1, kth)
} }
function RandomizedSelect (items, left, right, i) { function RandomizedSelect(items, left, right, i) {
if (left === right) return items[left] if (left === right) return items[left]
const pivotIndex = RandomizedPartition(items, left, right) const pivotIndex = RandomizedPartition(items, left, right)
@ -31,13 +32,13 @@ function RandomizedSelect (items, left, right, i) {
return RandomizedSelect(items, pivotIndex + 1, right, i - k) return RandomizedSelect(items, pivotIndex + 1, right, i - k)
} }
function RandomizedPartition (items, left, right) { function RandomizedPartition(items, left, right) {
const rand = getRandomInt(left, right) const rand = getRandomInt(left, right)
Swap(items, rand, right) Swap(items, rand, right)
return Partition(items, left, right) return Partition(items, left, right)
} }
function Partition (items, left, right) { function Partition(items, left, right) {
const x = items[right] const x = items[right]
let pivotIndex = left - 1 let pivotIndex = left - 1
@ -53,12 +54,12 @@ function Partition (items, left, right) {
return pivotIndex + 1 return pivotIndex + 1
} }
function getRandomInt (min, max) { function getRandomInt(min, max) {
return Math.floor(Math.random() * (max - min + 1)) + min return Math.floor(Math.random() * (max - min + 1)) + min
} }
function Swap (arr, x, y) { function Swap(arr, x, y) {
[arr[x], arr[y]] = [arr[y], arr[x]] ;[arr[x], arr[y]] = [arr[y], arr[x]]
} }
export { QuickSelect } export { QuickSelect }

View File

@ -1,13 +1,14 @@
import { Reverse } from '../Reverse.js' import { Reverse } from '../Reverse.js'
import each from 'jest-each'
describe('reverse elements in an array', () => { describe('reverse elements in an array', () => {
each` it.each([
array | expected [[], []],
${[]} | ${[]} [[1], [1]],
${[1]} | ${[1]} [
${[1, 2, 3, 4]} | ${[4, 3, 2, 1]} [1, 2, 3, 4],
`.test('returns $expected when given $array', ({ array, expected }) => { [4, 3, 2, 1]
]
])('returns %j when given %j', (array, expected) => {
expect(Reverse(array)).toEqual(expected) expect(Reverse(array)).toEqual(expected)
}) })
}) })

View File

@ -1,24 +1,24 @@
class Graph { class Graph {
constructor () { constructor() {
this.adjacencyMap = {} this.adjacencyMap = {}
} }
addVertex (vertex) { addVertex(vertex) {
this.adjacencyMap[vertex] = [] this.adjacencyMap[vertex] = []
} }
containsVertex (vertex) { containsVertex(vertex) {
return typeof (this.adjacencyMap[vertex]) !== 'undefined' return typeof this.adjacencyMap[vertex] !== 'undefined'
} }
addEdge (vertex1, vertex2) { addEdge(vertex1, vertex2) {
if (this.containsVertex(vertex1) && this.containsVertex(vertex2)) { if (this.containsVertex(vertex1) && this.containsVertex(vertex2)) {
this.adjacencyMap[vertex1].push(vertex2) this.adjacencyMap[vertex1].push(vertex2)
this.adjacencyMap[vertex2].push(vertex1) this.adjacencyMap[vertex2].push(vertex1)
} }
} }
printGraph (output = value => console.log(value)) { printGraph(output = (value) => console.log(value)) {
const keys = Object.keys(this.adjacencyMap) const keys = Object.keys(this.adjacencyMap)
for (const i of keys) { for (const i of keys) {
const values = this.adjacencyMap[i] const values = this.adjacencyMap[i]
@ -34,13 +34,14 @@ class Graph {
* Prints the Breadth first traversal of the graph from source. * Prints the Breadth first traversal of the graph from source.
* @param {number} source The source vertex to start BFS. * @param {number} source The source vertex to start BFS.
*/ */
bfs (source, output = value => console.log(value)) { bfs(source, output = (value) => console.log(value)) {
const queue = [[source, 0]] // level of source is 0 const queue = [[source, 0]] // level of source is 0
const visited = new Set() const visited = new Set()
while (queue.length) { while (queue.length) {
const [node, level] = queue.shift() // remove the front of the queue const [node, level] = queue.shift() // remove the front of the queue
if (visited.has(node)) { // visited if (visited.has(node)) {
// visited
continue continue
} }
@ -56,8 +57,9 @@ class Graph {
* Prints the Depth first traversal of the graph from source. * Prints the Depth first traversal of the graph from source.
* @param {number} source The source vertex to start DFS. * @param {number} source The source vertex to start DFS.
*/ */
dfs (source, visited = new Set(), output = value => console.log(value)) { dfs(source, visited = new Set(), output = (value) => console.log(value)) {
if (visited.has(source)) { // visited if (visited.has(source)) {
// visited
return return
} }

View File

@ -2,7 +2,7 @@
class Graph { class Graph {
// defining vertex array and // defining vertex array and
// adjacent list // adjacent list
constructor (noOfVertices) { constructor(noOfVertices) {
this.noOfVertices = noOfVertices this.noOfVertices = noOfVertices
this.AdjList = new Map() this.AdjList = new Map()
} }
@ -17,7 +17,7 @@ class Graph {
// dfs(v) // dfs(v)
// add vertex to the graph // add vertex to the graph
addVertex (v) { addVertex(v) {
// initialize the adjacent list with a // initialize the adjacent list with a
// null array // null array
@ -25,7 +25,7 @@ class Graph {
} }
// add edge to the graph // add edge to the graph
addEdge (v, w) { addEdge(v, w) {
// get the list for vertex v and put the // get the list for vertex v and put the
// vertex w denoting edge between v and w // vertex w denoting edge between v and w
this.AdjList.get(v).push(w) this.AdjList.get(v).push(w)
@ -36,7 +36,7 @@ class Graph {
} }
// Prints the vertex and adjacency list // Prints the vertex and adjacency list
printGraph (output = value => console.log(value)) { printGraph(output = (value) => console.log(value)) {
// get all the vertices // get all the vertices
const getKeys = this.AdjList.keys() const getKeys = this.AdjList.keys()

View File

@ -1,18 +1,18 @@
class Graph { class Graph {
constructor () { constructor() {
this.adjacencyObject = {} this.adjacencyObject = {}
} }
addVertex (vertex) { addVertex(vertex) {
if (!this.adjacencyObject[vertex]) this.adjacencyObject[vertex] = [] if (!this.adjacencyObject[vertex]) this.adjacencyObject[vertex] = []
} }
addEdge (vertex1, vertex2) { addEdge(vertex1, vertex2) {
this.adjacencyObject[vertex1].push(vertex2) this.adjacencyObject[vertex1].push(vertex2)
this.adjacencyObject[vertex2].push(vertex1) this.adjacencyObject[vertex2].push(vertex1)
} }
removeEdge (vertex1, vertex2) { removeEdge(vertex1, vertex2) {
this.adjacencyObject[vertex1] = this.adjacencyObject[vertex1].filter( this.adjacencyObject[vertex1] = this.adjacencyObject[vertex1].filter(
(v) => v !== vertex2 (v) => v !== vertex2
) )
@ -21,7 +21,7 @@ class Graph {
) )
} }
removeVertex (vertex) { removeVertex(vertex) {
while (this.adjacencyObject[vertex].length) { while (this.adjacencyObject[vertex].length) {
const adjacentVertex = this.adjacencyObject[vertex].pop() const adjacentVertex = this.adjacencyObject[vertex].pop()
this.removeEdge(vertex, adjacentVertex) this.removeEdge(vertex, adjacentVertex)
@ -31,14 +31,14 @@ class Graph {
/** /**
* Return DFS (Depth First Search) List Using Recursive Method * Return DFS (Depth First Search) List Using Recursive Method
*/ */
DFS (start) { DFS(start) {
if (!start) return null if (!start) return null
const result = [] const result = []
const visited = {} const visited = {}
const adjacencyObject = this.adjacencyObject const adjacencyObject = this.adjacencyObject
function dfs (vertex) { function dfs(vertex) {
if (!vertex) return null if (!vertex) return null
visited[vertex] = true visited[vertex] = true
result.push(vertex) result.push(vertex)
@ -56,7 +56,7 @@ class Graph {
/** /**
* Return DFS(Depth First Search) List Using Iteration * Return DFS(Depth First Search) List Using Iteration
*/ */
DFSIterative (start) { DFSIterative(start) {
if (!start) return null if (!start) return null
const stack = [start] const stack = [start]
@ -80,7 +80,7 @@ class Graph {
return result return result
} }
BFS (start) { BFS(start) {
if (!start) return null if (!start) return null
const queue = [start] const queue = [start]

View File

@ -18,7 +18,7 @@ describe('Test Graph2', () => {
graph.addEdge('C', 'F') graph.addEdge('C', 'F')
it('Check adjacency lists', () => { it('Check adjacency lists', () => {
const mockFn = jest.fn() const mockFn = vi.fn()
graph.printGraph(mockFn) graph.printGraph(mockFn)
// Expect one call per vertex // Expect one call per vertex

View File

@ -19,12 +19,12 @@
*/ */
// Priority Queue Helper functions // Priority Queue Helper functions
const getParentPosition = position => Math.floor((position - 1) / 2) const getParentPosition = (position) => Math.floor((position - 1) / 2)
const getChildrenPositions = position => [2 * position + 1, 2 * position + 2] const getChildrenPositions = (position) => [2 * position + 1, 2 * position + 2]
class KeyPriorityQueue { class KeyPriorityQueue {
// Priority Queue class using Minimum Binary Heap // Priority Queue class using Minimum Binary Heap
constructor () { constructor() {
this._heap = [] this._heap = []
this.priorities = new Map() this.priorities = new Map()
} }
@ -33,7 +33,7 @@ class KeyPriorityQueue {
* Checks if the heap is empty * Checks if the heap is empty
* @returns boolean * @returns boolean
*/ */
isEmpty () { isEmpty() {
return this._heap.length === 0 return this._heap.length === 0
} }
@ -42,7 +42,7 @@ class KeyPriorityQueue {
* @param {*} key * @param {*} key
* @param {number} priority * @param {number} priority
*/ */
push (key, priority) { push(key, priority) {
this._heap.push(key) this._heap.push(key)
this.priorities.set(key, priority) this.priorities.set(key, priority)
this._shiftUp(this._heap.length - 1) this._shiftUp(this._heap.length - 1)
@ -52,7 +52,7 @@ class KeyPriorityQueue {
* Removes the element with least priority * Removes the element with least priority
* @returns the key of the element with least priority * @returns the key of the element with least priority
*/ */
pop () { pop() {
this._swap(0, this._heap.length - 1) this._swap(0, this._heap.length - 1)
const key = this._heap.pop() const key = this._heap.pop()
this.priorities.delete(key) this.priorities.delete(key)
@ -65,7 +65,7 @@ class KeyPriorityQueue {
* @param {*} key * @param {*} key
* @returns boolean * @returns boolean
*/ */
contains (key) { contains(key) {
return this.priorities.has(key) return this.priorities.has(key)
} }
@ -75,7 +75,7 @@ class KeyPriorityQueue {
* @param {*} key the element to change * @param {*} key the element to change
* @param {number} priority new priority of the element * @param {number} priority new priority of the element
*/ */
update (key, priority) { update(key, priority) {
const currPos = this._heap.indexOf(key) const currPos = this._heap.indexOf(key)
// if the key does not exist yet, add it // if the key does not exist yet, add it
if (currPos === -1) return this.push(key, priority) if (currPos === -1) return this.push(key, priority)
@ -95,13 +95,14 @@ class KeyPriorityQueue {
} }
} }
_getPriorityOrInfinite (position) { _getPriorityOrInfinite(position) {
// Helper function, returns priority of the node, or Infinite if no node corresponds to this position // Helper function, returns priority of the node, or Infinite if no node corresponds to this position
if (position >= 0 && position < this._heap.length) return this.priorities.get(this._heap[position]) if (position >= 0 && position < this._heap.length)
return this.priorities.get(this._heap[position])
else return Infinity else return Infinity
} }
_shiftUp (position) { _shiftUp(position) {
// Helper function to shift up a node to proper position (equivalent to bubbleUp) // Helper function to shift up a node to proper position (equivalent to bubbleUp)
let currPos = position let currPos = position
let parentPos = getParentPosition(currPos) let parentPos = getParentPosition(currPos)
@ -117,7 +118,7 @@ class KeyPriorityQueue {
} }
} }
_shiftDown (position) { _shiftDown(position) {
// Helper function to shift down a node to proper position (equivalent to bubbleDown) // Helper function to shift down a node to proper position (equivalent to bubbleDown)
let currPos = position let currPos = position
let [child1Pos, child2Pos] = getChildrenPositions(currPos) let [child1Pos, child2Pos] = getChildrenPositions(currPos)
@ -137,16 +138,19 @@ class KeyPriorityQueue {
this._swap(child2Pos, currPos) this._swap(child2Pos, currPos)
currPos = child2Pos currPos = child2Pos
} }
[child1Pos, child2Pos] = getChildrenPositions(currPos) ;[child1Pos, child2Pos] = getChildrenPositions(currPos)
child1Priority = this._getPriorityOrInfinite(child1Pos) child1Priority = this._getPriorityOrInfinite(child1Pos)
child2Priority = this._getPriorityOrInfinite(child2Pos) child2Priority = this._getPriorityOrInfinite(child2Pos)
currPriority = this._getPriorityOrInfinite(currPos) currPriority = this._getPriorityOrInfinite(currPos)
} }
} }
_swap (position1, position2) { _swap(position1, position2) {
// Helper function to swap 2 nodes // Helper function to swap 2 nodes
[this._heap[position1], this._heap[position2]] = [this._heap[position2], this._heap[position1]] ;[this._heap[position1], this._heap[position2]] = [
this._heap[position2],
this._heap[position1]
]
} }
} }

View File

@ -4,25 +4,25 @@
*/ */
class BinaryHeap { class BinaryHeap {
constructor () { constructor() {
this.heap = [] this.heap = []
} }
insert (value) { insert(value) {
this.heap.push(value) this.heap.push(value)
this.heapify() this.heapify()
} }
size () { size() {
return this.heap.length return this.heap.length
} }
empty () { empty() {
return this.size() === 0 return this.size() === 0
} }
// using iterative approach to reorder the heap after insertion // using iterative approach to reorder the heap after insertion
heapify () { heapify() {
let index = this.size() - 1 let index = this.size() - 1
while (index > 0) { while (index > 0) {
@ -38,7 +38,7 @@ class BinaryHeap {
} }
// Extracting the maximum element from the Heap // Extracting the maximum element from the Heap
extractMax () { extractMax() {
const max = this.heap[0] const max = this.heap[0]
const tmp = this.heap.pop() const tmp = this.heap.pop()
if (!this.empty()) { if (!this.empty()) {
@ -49,7 +49,7 @@ class BinaryHeap {
} }
// To restore the balance of the heap after extraction. // To restore the balance of the heap after extraction.
sinkDown (index) { sinkDown(index) {
const left = 2 * index + 1 const left = 2 * index + 1
const right = 2 * index + 2 const right = 2 * index + 2
let largest = index let largest = index

View File

@ -19,7 +19,7 @@
*/ */
class MinHeap { class MinHeap {
constructor (array) { constructor(array) {
this.heap = this.initializeHeap(array) this.heap = this.initializeHeap(array)
} }
@ -27,7 +27,7 @@ class MinHeap {
* startingParent represents the parent of the last index (=== array.length-1) * startingParent represents the parent of the last index (=== array.length-1)
* and iterates towards 0 with all index values below sorted to meet heap conditions * and iterates towards 0 with all index values below sorted to meet heap conditions
*/ */
initializeHeap (array) { initializeHeap(array) {
const startingParent = Math.floor((array.length - 2) / 2) const startingParent = Math.floor((array.length - 2) / 2)
for (let currIdx = startingParent; currIdx >= 0; currIdx--) { for (let currIdx = startingParent; currIdx >= 0; currIdx--) {
@ -53,12 +53,13 @@ class MinHeap {
* *
* if there is no swap, it means the children indices and the parent index satisfy heap conditions and can exit the function. * if there is no swap, it means the children indices and the parent index satisfy heap conditions and can exit the function.
*/ */
sinkDown (currIdx, endIdx, heap) { sinkDown(currIdx, endIdx, heap) {
let childOneIdx = currIdx * 2 + 1 let childOneIdx = currIdx * 2 + 1
while (childOneIdx <= endIdx) { while (childOneIdx <= endIdx) {
const childTwoIdx = childOneIdx + 1 <= endIdx ? childOneIdx + 1 : -1 const childTwoIdx = childOneIdx + 1 <= endIdx ? childOneIdx + 1 : -1
const swapIdx = childTwoIdx !== -1 && heap[childTwoIdx] < heap[childOneIdx] const swapIdx =
childTwoIdx !== -1 && heap[childTwoIdx] < heap[childOneIdx]
? childTwoIdx ? childTwoIdx
: childOneIdx : childOneIdx
@ -80,7 +81,7 @@ class MinHeap {
* *
* iteration does not end while a valid currIdx has a value smaller than its parentIdx's value * iteration does not end while a valid currIdx has a value smaller than its parentIdx's value
*/ */
bubbleUp (currIdx) { bubbleUp(currIdx) {
let parentIdx = Math.floor((currIdx - 1) / 2) let parentIdx = Math.floor((currIdx - 1) / 2)
while (currIdx > 0 && this.heap[currIdx] < this.heap[parentIdx]) { while (currIdx > 0 && this.heap[currIdx] < this.heap[parentIdx]) {
@ -90,7 +91,7 @@ class MinHeap {
} }
} }
peek () { peek() {
return this.heap[0] return this.heap[0]
} }
@ -102,7 +103,7 @@ class MinHeap {
* *
* the remaining values in the heap are re-sorted * the remaining values in the heap are re-sorted
*/ */
extractMin () { extractMin() {
this.swap(0, this.heap.length - 1, this.heap) this.swap(0, this.heap.length - 1, this.heap)
const min = this.heap.pop() const min = this.heap.pop()
this.sinkDown(0, this.heap.length - 1, this.heap) this.sinkDown(0, this.heap.length - 1, this.heap)
@ -110,13 +111,13 @@ class MinHeap {
} }
// a new value is pushed to the end of the heap and sorted up // a new value is pushed to the end of the heap and sorted up
insert (value) { insert(value) {
this.heap.push(value) this.heap.push(value)
this.bubbleUp(this.heap.length - 1) this.bubbleUp(this.heap.length - 1)
} }
// index-swapping helper method // index-swapping helper method
swap (idx1, idx2, heap) { swap(idx1, idx2, heap) {
const temp = heap[idx1] const temp = heap[idx1]
heap[idx1] = heap[idx2] heap[idx1] = heap[idx2]
heap[idx2] = temp heap[idx2] = temp

View File

@ -1,18 +1,18 @@
/* Minimum Priority Queue /* Minimum Priority Queue
* It is a part of heap data structure * It is a part of heap data structure
* A heap is a specific tree based data structure * A heap is a specific tree based data structure
* in which all the nodes of tree are in a specific order. * in which all the nodes of tree are in a specific order.
* that is the children are arranged in some * that is the children are arranged in some
* respect of their parents, can either be greater * respect of their parents, can either be greater
* or less than the parent. This makes it a min priority queue * or less than the parent. This makes it a min priority queue
* or max priority queue. * or max priority queue.
*/ */
// Functions: insert, delete, peek, isEmpty, print, heapSort, sink // Functions: insert, delete, peek, isEmpty, print, heapSort, sink
class MinPriorityQueue { class MinPriorityQueue {
// calls the constructor and initializes the capacity // calls the constructor and initializes the capacity
constructor (c) { constructor(c) {
this.heap = [] this.heap = []
this.capacity = c this.capacity = c
this.size = 0 this.size = 0
@ -20,7 +20,7 @@ class MinPriorityQueue {
// inserts the key at the end and rearranges it // inserts the key at the end and rearranges it
// so that the binary heap is in appropriate order // so that the binary heap is in appropriate order
insert (key) { insert(key) {
if (this.isFull()) return if (this.isFull()) return
this.heap[this.size + 1] = key this.heap[this.size + 1] = key
let k = this.size + 1 let k = this.size + 1
@ -36,33 +36,36 @@ class MinPriorityQueue {
} }
// returns the highest priority value // returns the highest priority value
peek () { peek() {
return this.heap[1] return this.heap[1]
} }
// returns boolean value whether the heap is empty or not // returns boolean value whether the heap is empty or not
isEmpty () { isEmpty() {
return this.size === 0 return this.size === 0
} }
// returns boolean value whether the heap is full or not // returns boolean value whether the heap is full or not
isFull () { isFull() {
return this.size === this.capacity return this.size === this.capacity
} }
// prints the heap // prints the heap
print (output = value => console.log(value)) { print(output = (value) => console.log(value)) {
output(this.heap.slice(1)) output(this.heap.slice(1))
} }
// heap reverse can be done by performing swapping the first // heap reverse can be done by performing swapping the first
// element with the last, removing the last element to // element with the last, removing the last element to
// new array and calling sink function. // new array and calling sink function.
heapReverse () { heapReverse() {
const heapSort = [] const heapSort = []
while (this.size > 0) { while (this.size > 0) {
// swap first element with last element // swap first element with last element
[this.heap[1], this.heap[this.size]] = [this.heap[this.size], this.heap[1]] ;[this.heap[1], this.heap[this.size]] = [
this.heap[this.size],
this.heap[1]
]
heapSort.push(this.heap.pop()) heapSort.push(this.heap.pop())
this.size-- this.size--
this.sink() this.sink()
@ -74,7 +77,7 @@ class MinPriorityQueue {
} }
// this function reorders the heap after every delete function // this function reorders the heap after every delete function
sink () { sink() {
let k = 1 let k = 1
while (2 * k <= this.size || 2 * k + 1 <= this.size) { while (2 * k <= this.size || 2 * k + 1 <= this.size) {
let minIndex let minIndex
@ -92,8 +95,7 @@ class MinPriorityQueue {
this.heap[k] > this.heap[2 * k] || this.heap[k] > this.heap[2 * k] ||
this.heap[k] > this.heap[2 * k + 1] this.heap[k] > this.heap[2 * k + 1]
) { ) {
minIndex = minIndex = this.heap[2 * k] < this.heap[2 * k + 1] ? 2 * k : 2 * k + 1
this.heap[2 * k] < this.heap[2 * k + 1] ? 2 * k : 2 * k + 1
} else { } else {
minIndex = k minIndex = k
} }
@ -107,7 +109,7 @@ class MinPriorityQueue {
// deletes the highest priority value from the heap. The last // deletes the highest priority value from the heap. The last
// element goes to ahead to first position and reorder heap // element goes to ahead to first position and reorder heap
delete () { delete() {
// checks empty and one element array conditions // checks empty and one element array conditions
if (this.isEmpty()) return if (this.isEmpty()) return
if (this.size === 1) { if (this.size === 1) {

View File

@ -9,7 +9,9 @@ describe('MinHeap', () => {
}) })
it('should initialize a heap from an input array', () => { it('should initialize a heap from an input array', () => {
expect(heap).toEqual({ 'heap': [1, 4, 2, 7, 16, 10, 39, 23, 9, 43, 85, 42, 51] }) // eslint-disable-line expect(heap).toEqual({
heap: [1, 4, 2, 7, 16, 10, 39, 23, 9, 43, 85, 42, 51]
}) // eslint-disable-line
}) })
it('should show the top value in the heap', () => { it('should show the top value in the heap', () => {
@ -22,12 +24,14 @@ describe('MinHeap', () => {
const minValue = heap.extractMin() const minValue = heap.extractMin()
expect(minValue).toEqual(1) expect(minValue).toEqual(1)
expect(heap).toEqual({ 'heap': [2, 4, 10, 7, 16, 42, 39, 23, 9, 43, 85, 51] }) // eslint-disable-line expect(heap).toEqual({ heap: [2, 4, 10, 7, 16, 42, 39, 23, 9, 43, 85, 51] }) // eslint-disable-line
}) })
it('should insert a new value and sort until it meets heap conditions', () => { it('should insert a new value and sort until it meets heap conditions', () => {
heap.insert(15) heap.insert(15)
expect(heap).toEqual({ 'heap': [2, 4, 10, 7, 16, 15, 39, 23, 9, 43, 85, 51, 42] }) // eslint-disable-line expect(heap).toEqual({
heap: [2, 4, 10, 7, 16, 15, 39, 23, 9, 43, 85, 51, 42]
}) // eslint-disable-line
}) })
}) })

View File

@ -7,11 +7,11 @@ describe('MinPriorityQueue', () => {
beforeEach(() => { beforeEach(() => {
queue = new MinPriorityQueue(capacity) queue = new MinPriorityQueue(capacity)
values.forEach(v => queue.insert(v)) values.forEach((v) => queue.insert(v))
}) })
it('Check heap ordering', () => { it('Check heap ordering', () => {
const mockFn = jest.fn() const mockFn = vi.fn()
queue.print(mockFn) queue.print(mockFn)
expect(mockFn.mock.calls.length).toBe(1) // Expect one call expect(mockFn.mock.calls.length).toBe(1) // Expect one call
@ -24,7 +24,7 @@ describe('MinPriorityQueue', () => {
it('heapSort() expected to reverse the heap ordering', () => { it('heapSort() expected to reverse the heap ordering', () => {
queue.heapReverse() queue.heapReverse()
const mockFn = jest.fn() const mockFn = vi.fn()
queue.print(mockFn) queue.print(mockFn)
expect(mockFn.mock.calls.length).toBe(1) expect(mockFn.mock.calls.length).toBe(1)

View File

@ -14,11 +14,11 @@ Link for the Problem: https://leetcode.com/problems/add-two-numbers/
*/ */
class AddTwoNumbers { class AddTwoNumbers {
constructor () { constructor() {
this.dummyNode = new Node(0) this.dummyNode = new Node(0)
} }
solution (firstList, secondList) { solution(firstList, secondList) {
let firstRunner = firstList let firstRunner = firstList
let secondRunner = secondList let secondRunner = secondList
let tail = this.dummyNode let tail = this.dummyNode
@ -44,7 +44,7 @@ class AddTwoNumbers {
return this.dummyNode.next return this.dummyNode.next
} }
solutionToArray () { solutionToArray() {
const list = [] const list = []
let currentNode = this.dummyNode.next let currentNode = this.dummyNode.next
while (currentNode) { while (currentNode) {

View File

@ -3,18 +3,22 @@
* https://en.wikipedia.org/wiki/Cycle_detection * https://en.wikipedia.org/wiki/Cycle_detection
*/ */
function detectCycle (head) { function detectCycle(head) {
/* /*
Problem Statement: Problem Statement:
Given head, the head of a linked list, determine if the linked list has a cycle in it. Given head, the head of a linked list, determine if the linked list has a cycle in it.
Link for the Problem: https://leetcode.com/problems/linked-list-cycle/ Link for the Problem: https://leetcode.com/problems/linked-list-cycle/
*/ */
if (!head) { return false } if (!head) {
return false
}
let slow = head let slow = head
let fast = head.next let fast = head.next
while (fast && fast.next) { while (fast && fast.next) {
if (fast === slow) { return true } if (fast === slow) {
return true
}
fast = fast.next.next fast = fast.next.next
slow = slow.next slow = slow.next
} }

View File

@ -1,5 +1,5 @@
class Node { class Node {
constructor (element) { constructor(element) {
this.element = element this.element = element
this.next = null this.next = null
this.prev = null this.prev = null
@ -7,14 +7,14 @@ class Node {
} }
class DoubleLinkedList { class DoubleLinkedList {
constructor () { constructor() {
this.length = 0 this.length = 0
this.head = null this.head = null
this.tail = null this.tail = null
} }
// Add new element // Add new element
append (element) { append(element) {
const node = new Node(element) const node = new Node(element)
if (!this.head) { if (!this.head) {
@ -30,7 +30,7 @@ class DoubleLinkedList {
} }
// Add element // Add element
insert (position, element) { insert(position, element) {
// Check of out-of-bound values // Check of out-of-bound values
if (position >= 0 && position <= this.length) { if (position >= 0 && position <= this.length) {
const node = new Node(element) const node = new Node(element)
@ -74,7 +74,7 @@ class DoubleLinkedList {
} }
// Remove element at any position // Remove element at any position
removeAt (position) { removeAt(position) {
// look for out-of-bounds value // look for out-of-bounds value
if (position > -1 && position < this.length) { if (position > -1 && position < this.length) {
let current = this.head let current = this.head
@ -114,7 +114,7 @@ class DoubleLinkedList {
} }
// Get the indexOf item // Get the indexOf item
indexOf (elm) { indexOf(elm) {
let current = this.head let current = this.head
let index = -1 let index = -1
@ -133,27 +133,27 @@ class DoubleLinkedList {
} }
// Find the item in the list // Find the item in the list
isPresent (elm) { isPresent(elm) {
return this.indexOf(elm) !== -1 return this.indexOf(elm) !== -1
} }
// Delete an item from the list // Delete an item from the list
delete (elm) { delete(elm) {
return this.removeAt(this.indexOf(elm)) return this.removeAt(this.indexOf(elm))
} }
// Delete first item from the list // Delete first item from the list
deleteHead () { deleteHead() {
this.removeAt(0) this.removeAt(0)
} }
// Delete last item from the list // Delete last item from the list
deleteTail () { deleteTail() {
this.removeAt(this.length - 1) this.removeAt(this.length - 1)
} }
// Print item of the string // Print item of the string
toString () { toString() {
let current = this.head let current = this.head
let string = '' let string = ''
@ -166,7 +166,7 @@ class DoubleLinkedList {
} }
// Convert list to array // Convert list to array
toArray () { toArray() {
const arr = [] const arr = []
let current = this.head let current = this.head
@ -179,31 +179,31 @@ class DoubleLinkedList {
} }
// Check if list is empty // Check if list is empty
isEmpty () { isEmpty() {
return this.length === 0 return this.length === 0
} }
// Get the size of the list // Get the size of the list
size () { size() {
return this.length return this.length
} }
// Get the this.head // Get the this.head
getHead () { getHead() {
return this.head return this.head
} }
// Get the this.tail // Get the this.tail
getTail () { getTail() {
return this.tail return this.tail
} }
// Method to iterate over the LinkedList // Method to iterate over the LinkedList
iterator () { iterator() {
let currentNode = this.getHead() let currentNode = this.getHead()
if (currentNode === null) return -1 if (currentNode === null) return -1
const iterate = function * () { const iterate = function* () {
while (currentNode) { while (currentNode) {
yield currentNode.element yield currentNode.element
currentNode = currentNode.next currentNode = currentNode.next
@ -214,7 +214,7 @@ class DoubleLinkedList {
// Method to log the LinkedList, for debugging // Method to log the LinkedList, for debugging
// it' a circular structure, so can't use stringify to debug the whole structure // it' a circular structure, so can't use stringify to debug the whole structure
log () { log() {
let currentNode = this.getHead() let currentNode = this.getHead()
while (currentNode) { while (currentNode) {
console.log(currentNode.element) console.log(currentNode.element)

View File

@ -1,7 +1,7 @@
/** A LinkedList based solution to reverse a number /** A LinkedList based solution to reverse a number
Problem Statement: Given a number such that each of its digit is stored in a singly linked list. Reverse the linked list and return the head of the linked list Link for the Problem: https://leetcode.com/problems/reverse-linked-list/ */ Problem Statement: Given a number such that each of its digit is stored in a singly linked list. Reverse the linked list and return the head of the linked list Link for the Problem: https://leetcode.com/problems/reverse-linked-list/ */
class ReverseSinglyLinkedList { class ReverseSinglyLinkedList {
solution (head) { solution(head) {
let prev = null let prev = null
let next = null let next = null
while (head) { while (head) {
@ -11,6 +11,6 @@ class ReverseSinglyLinkedList {
head = next head = next
} }
return prev return prev
}; }
} }
export { ReverseSinglyLinkedList } export { ReverseSinglyLinkedList }

View File

@ -2,7 +2,7 @@
import { Node } from './SinglyLinkedList.js' import { Node } from './SinglyLinkedList.js'
class SinglyCircularLinkedList { class SinglyCircularLinkedList {
constructor () { constructor() {
this.headNode = null this.headNode = null
this.length = 0 this.length = 0
} }
@ -15,12 +15,12 @@ class SinglyCircularLinkedList {
isEmpty = () => this.length === 0 isEmpty = () => this.length === 0
// initiate the node and index // initiate the node and index
initiateNodeAndIndex () { initiateNodeAndIndex() {
return { currentNode: this.headNode, currentIndex: 0 } return { currentNode: this.headNode, currentIndex: 0 }
} }
// get the data specific to an index // get the data specific to an index
getElementAt (index) { getElementAt(index) {
if (this.length !== 0 && index >= 0 && index <= this.length) { if (this.length !== 0 && index >= 0 && index <= this.length) {
let { currentNode } = this.initiateNodeAndIndex() let { currentNode } = this.initiateNodeAndIndex()
for (let i = 0; i < index && currentNode !== null; i++) { for (let i = 0; i < index && currentNode !== null; i++) {
@ -32,7 +32,7 @@ class SinglyCircularLinkedList {
} }
// Add the element in the first position // Add the element in the first position
addAtFirst (data) { addAtFirst(data) {
const node = new Node(data) const node = new Node(data)
node.next = this.headNode node.next = this.headNode
this.headNode = node this.headNode = node
@ -41,8 +41,10 @@ class SinglyCircularLinkedList {
} }
// Add any data to the end of the linkedList // Add any data to the end of the linkedList
add (data) { add(data) {
if (!this.headNode) { return this.addAtFirst(data) } if (!this.headNode) {
return this.addAtFirst(data)
}
const node = new Node(data) const node = new Node(data)
// Getting the last node // Getting the last node
const currentNode = this.getElementAt(this.length - 1) const currentNode = this.getElementAt(this.length - 1)
@ -53,10 +55,11 @@ class SinglyCircularLinkedList {
} }
// insert data at a specific position // insert data at a specific position
insertAt (index, data) { insertAt(index, data) {
if (index === 0) return this.addAtFirst(data) if (index === 0) return this.addAtFirst(data)
if (index === this.length) return this.add(data) if (index === this.length) return this.add(data)
if (index < 0 || index > this.length) throw new RangeError(`Index is out of range max ${this.length}`) if (index < 0 || index > this.length)
throw new RangeError(`Index is out of range max ${this.length}`)
const node = new Node(data) const node = new Node(data)
const previousNode = this.getElementAt(index - 1) const previousNode = this.getElementAt(index - 1)
node.next = previousNode.next node.next = previousNode.next
@ -66,7 +69,7 @@ class SinglyCircularLinkedList {
} }
// find the first index of the data // find the first index of the data
indexOf (data) { indexOf(data) {
let { currentNode } = this.initiateNodeAndIndex() let { currentNode } = this.initiateNodeAndIndex()
// initializing currentIndex as -1 // initializing currentIndex as -1
let currentIndex = -1 let currentIndex = -1
@ -81,7 +84,7 @@ class SinglyCircularLinkedList {
} }
// remove the data from the end of the list // remove the data from the end of the list
remove () { remove() {
if (this.isEmpty()) return null if (this.isEmpty()) return null
const secondLastNode = this.getElementAt(this.length - 2) const secondLastNode = this.getElementAt(this.length - 2)
const removedNode = secondLastNode.next const removedNode = secondLastNode.next
@ -91,7 +94,7 @@ class SinglyCircularLinkedList {
} }
// remove the data from the first of the list // remove the data from the first of the list
removeFirst () { removeFirst() {
if (this.isEmpty()) return null if (this.isEmpty()) return null
const removedNode = this.headNode const removedNode = this.headNode
if (this.length === 1) { if (this.length === 1) {
@ -106,7 +109,7 @@ class SinglyCircularLinkedList {
} }
// remove the data from the index // remove the data from the index
removeAt (index) { removeAt(index) {
if (this.isEmpty()) return null if (this.isEmpty()) return null
if (index === 0) return this.removeFirst() if (index === 0) return this.removeFirst()
if (index === this.length) return this.remove() if (index === this.length) return this.remove()
@ -119,14 +122,14 @@ class SinglyCircularLinkedList {
} }
// remove if the data is present // remove if the data is present
removeData (data) { removeData(data) {
if (this.isEmpty()) return null if (this.isEmpty()) return null
const index = this.indexOf(data) const index = this.indexOf(data)
return this.removeAt(index) return this.removeAt(index)
} }
// logs the data // logs the data
printData (output = value => console.log(value)) { printData(output = (value) => console.log(value)) {
let { currentIndex, currentNode } = this.initiateNodeAndIndex() let { currentIndex, currentNode } = this.initiateNodeAndIndex()
while (currentNode !== null && currentIndex < this.length) { while (currentNode !== null && currentIndex < this.length) {
@ -137,7 +140,7 @@ class SinglyCircularLinkedList {
} }
// get the data from the linkedList // get the data from the linkedList
get () { get() {
let { currentIndex, currentNode } = this.initiateNodeAndIndex() let { currentIndex, currentNode } = this.initiateNodeAndIndex()
const list = [] const list = []
while (currentNode !== null && currentIndex < this.length) { while (currentNode !== null && currentIndex < this.length) {
@ -148,7 +151,7 @@ class SinglyCircularLinkedList {
return list return list
} }
clear () { clear() {
this.headNode = null this.headNode = null
this.length = 0 this.length = 0
} }

View File

@ -9,14 +9,14 @@
// Methods - size, head, addLast, addFirst, addAt, removeFirst, removeLast, remove, removeAt, indexOf, isEmpty, elementAt, findMiddle, get, clean, rotateListRight // Methods - size, head, addLast, addFirst, addAt, removeFirst, removeLast, remove, removeAt, indexOf, isEmpty, elementAt, findMiddle, get, clean, rotateListRight
class Node { class Node {
constructor (data) { constructor(data) {
this.data = data this.data = data
this.next = null this.next = null
} }
} }
class LinkedList { class LinkedList {
constructor (listOfValues) { constructor(listOfValues) {
this.headNode = null this.headNode = null
this.tailNode = null this.tailNode = null
this.length = 0 this.length = 0
@ -29,32 +29,32 @@ class LinkedList {
} }
// initiates the currentNode and currentIndex and return as an object // initiates the currentNode and currentIndex and return as an object
initiateNodeAndIndex () { initiateNodeAndIndex() {
return { currentNode: this.headNode, currentIndex: 0 } return { currentNode: this.headNode, currentIndex: 0 }
} }
// Returns length // Returns length
size () { size() {
return this.length return this.length
} }
// Returns the head // Returns the head
head () { head() {
return this.headNode?.data ?? null return this.headNode?.data ?? null
} }
// Returns the tail // Returns the tail
tail () { tail() {
return this.tailNode?.data ?? null return this.tailNode?.data ?? null
} }
// Return if the list is empty // Return if the list is empty
isEmpty () { isEmpty() {
return this.length === 0 return this.length === 0
} }
// add a node at last it to linklist // add a node at last it to linklist
addLast (element) { addLast(element) {
// Check if its the first element // Check if its the first element
if (this.headNode === null) { if (this.headNode === null) {
return this.addFirst(element) return this.addFirst(element)
@ -68,7 +68,7 @@ class LinkedList {
} }
// add a node at first it to linklist // add a node at first it to linklist
addFirst (element) { addFirst(element) {
const node = new Node(element) const node = new Node(element)
// Check if its the first element // Check if its the first element
if (this.headNode === null) { if (this.headNode === null) {
@ -82,7 +82,7 @@ class LinkedList {
} }
// remove the first from the linklist // remove the first from the linklist
removeFirst () { removeFirst() {
// Check if head is null // Check if head is null
if (this.headNode === null) { if (this.headNode === null) {
return null return null
@ -99,7 +99,7 @@ class LinkedList {
} }
// remove the last from the linklist // remove the last from the linklist
removeLast () { removeLast() {
if (this.isEmpty()) return null if (this.isEmpty()) return null
// Check if there is only one element // Check if there is only one element
if (this.length === 1) { if (this.length === 1) {
@ -118,7 +118,7 @@ class LinkedList {
} }
// Removes the node with the value as param // Removes the node with the value as param
remove (element) { remove(element) {
if (this.isEmpty()) return null if (this.isEmpty()) return null
let { currentNode } = this.initiateNodeAndIndex() let { currentNode } = this.initiateNodeAndIndex()
let removedNode = null let removedNode = null
@ -144,7 +144,7 @@ class LinkedList {
} }
// Returns the index of the element passed as param otherwise -1 // Returns the index of the element passed as param otherwise -1
indexOf (element) { indexOf(element) {
if (this.isEmpty()) return -1 if (this.isEmpty()) return -1
let { currentNode, currentIndex } = this.initiateNodeAndIndex() let { currentNode, currentIndex } = this.initiateNodeAndIndex()
while (currentNode) { while (currentNode) {
@ -158,7 +158,7 @@ class LinkedList {
} }
// Returns the element at an index // Returns the element at an index
elementAt (index) { elementAt(index) {
if (index >= this.length || index < 0) { if (index >= this.length || index < 0) {
throw new RangeError('Out of Range index') throw new RangeError('Out of Range index')
} }
@ -171,7 +171,7 @@ class LinkedList {
} }
// Adds the element at specified index // Adds the element at specified index
addAt (index, element) { addAt(index, element) {
// Check if index is out of bounds of list // Check if index is out of bounds of list
if (index > this.length || index < 0) { if (index > this.length || index < 0) {
throw new RangeError('Out of Range index') throw new RangeError('Out of Range index')
@ -196,7 +196,7 @@ class LinkedList {
} }
// Removes the node at specified index // Removes the node at specified index
removeAt (index) { removeAt(index) {
// Check if index is present in list // Check if index is present in list
if (index < 0 || index >= this.length) { if (index < 0 || index >= this.length) {
throw new RangeError('Out of Range index') throw new RangeError('Out of Range index')
@ -216,7 +216,7 @@ class LinkedList {
} }
// Returns a reference to middle node of linked list // Returns a reference to middle node of linked list
findMiddle () { findMiddle() {
// If there are two middle nodes, return the second middle node. // If there are two middle nodes, return the second middle node.
let fast = this.headNode let fast = this.headNode
let slow = this.headNode let slow = this.headNode
@ -229,14 +229,14 @@ class LinkedList {
} }
// make the linkedList Empty // make the linkedList Empty
clean () { clean() {
this.headNode = null this.headNode = null
this.tailNode = null this.tailNode = null
this.length = 0 this.length = 0
} }
// Method to get the LinkedList // Method to get the LinkedList
get () { get() {
const list = [] const list = []
let { currentNode } = this.initiateNodeAndIndex() let { currentNode } = this.initiateNodeAndIndex()
while (currentNode) { while (currentNode) {
@ -247,7 +247,7 @@ class LinkedList {
} }
// Method for Rotating a List to the right by k places // Method for Rotating a List to the right by k places
rotateListRight (k) { rotateListRight(k) {
if (!this.headNode) return if (!this.headNode) return
let current = this.headNode let current = this.headNode
let tail = this.tailNode let tail = this.tailNode
@ -268,11 +268,11 @@ class LinkedList {
} }
// Method to iterate over the LinkedList // Method to iterate over the LinkedList
iterator () { iterator() {
let { currentNode } = this.initiateNodeAndIndex() let { currentNode } = this.initiateNodeAndIndex()
if (currentNode === null) return -1 if (currentNode === null) return -1
const iterate = function * () { const iterate = function* () {
while (currentNode) { while (currentNode) {
yield currentNode.data yield currentNode.data
currentNode = currentNode.next currentNode = currentNode.next
@ -282,12 +282,12 @@ class LinkedList {
} }
// Method to log the LinkedList // Method to log the LinkedList
log () { log() {
console.log(JSON.stringify(this.headNode, null, 2)) console.log(JSON.stringify(this.headNode, null, 2))
} }
// Method to reverse the LinkedList // Method to reverse the LinkedList
reverse () { reverse() {
let head = this.headNode let head = this.headNode
let prev = null let prev = null
let next = null let next = null
@ -299,7 +299,7 @@ class LinkedList {
} }
this.tailNode = this.headNode this.tailNode = this.headNode
this.headNode = prev this.headNode = prev
}; }
} }
export { Node, LinkedList } export { Node, LinkedList }

View File

@ -4,7 +4,7 @@
// Doesnt use dynamic memory so No memory leaks // Doesnt use dynamic memory so No memory leaks
class CircularQueue { class CircularQueue {
constructor (maxLength) { constructor(maxLength) {
this.queue = [] this.queue = []
this.front = 0 this.front = 0
this.rear = 0 this.rear = 0
@ -12,7 +12,7 @@ class CircularQueue {
} }
// ADD ELEMENTS TO QUEUE // ADD ELEMENTS TO QUEUE
enqueue (value) { enqueue(value) {
if (this.checkOverflow()) return if (this.checkOverflow()) return
if (this.checkEmpty()) { if (this.checkEmpty()) {
this.front += 1 this.front += 1
@ -26,7 +26,7 @@ class CircularQueue {
} }
// REMOVES ELEMENTS // REMOVES ELEMENTS
dequeue () { dequeue() {
if (this.checkEmpty()) { if (this.checkEmpty()) {
// UNDERFLOW // UNDERFLOW
return return
@ -44,13 +44,13 @@ class CircularQueue {
} }
// checks if the queue is empty or not // checks if the queue is empty or not
checkEmpty () { checkEmpty() {
if (this.front === 0 && this.rear === 0) { if (this.front === 0 && this.rear === 0) {
return true return true
} }
} }
checkSingleelement () { checkSingleelement() {
if (this.front === this.rear && this.rear !== 0) { if (this.front === this.rear && this.rear !== 0) {
this.front = this.rear = 0 this.front = this.rear = 0
return true return true
@ -58,27 +58,30 @@ class CircularQueue {
} }
// Checks if max capacity of queue has been reached or not // Checks if max capacity of queue has been reached or not
checkOverflow () { checkOverflow() {
if ((this.front === 1 && this.rear === this.maxLength) || (this.front === this.rear + 1)) { if (
(this.front === 1 && this.rear === this.maxLength) ||
this.front === this.rear + 1
) {
// CIRCULAR QUEUE OVERFLOW // CIRCULAR QUEUE OVERFLOW
return true return true
} }
} }
// Prints the entire array ('*' represents blank space) // Prints the entire array ('*' represents blank space)
display (output = value => console.log(value)) { display(output = (value) => console.log(value)) {
for (let index = 1; index < this.queue.length; index++) { for (let index = 1; index < this.queue.length; index++) {
output(this.queue[index]) output(this.queue[index])
} }
} }
// Displays the length of queue // Displays the length of queue
length () { length() {
return this.queue.length - 1 return this.queue.length - 1
} }
// Display the top most value of queue // Display the top most value of queue
peek () { peek() {
return this.queue[this.front] return this.queue[this.front]
} }
} }

View File

@ -1,15 +1,15 @@
/* Queue /* Queue
* A Queue is a data structure that allows you to add an element to the end of * A Queue is a data structure that allows you to add an element to the end of
* a list and remove the item at the front. A queue follows a FIFO (First In First Out) * a list and remove the item at the front. A queue follows a FIFO (First In First Out)
* system, where the first item to enter the queue is the first to be removed, * system, where the first item to enter the queue is the first to be removed,
* All these operation complexities are O(1). * All these operation complexities are O(1).
* This implementation following the linked list structure. * This implementation following the linked list structure.
*/ */
class Queue { class Queue {
#size #size
constructor () { constructor() {
this.head = null this.head = null
this.tail = null this.tail = null
this.#size = 0 this.#size = 0
@ -17,7 +17,7 @@ class Queue {
return Object.seal(this) return Object.seal(this)
} }
get length () { get length() {
return this.#size return this.#size
} }
@ -26,7 +26,7 @@ class Queue {
* @param {*} data * @param {*} data
* @returns {number} - The current size of queue * @returns {number} - The current size of queue
*/ */
enqueue (data) { enqueue(data) {
const node = { data, next: null } const node = { data, next: null }
if (!this.head && !this.tail) { if (!this.head && !this.tail) {
@ -44,7 +44,7 @@ class Queue {
* @description - Removes the value at the front of the queue * @description - Removes the value at the front of the queue
* @returns {*} - The first data of the queue * @returns {*} - The first data of the queue
*/ */
dequeue () { dequeue() {
if (this.isEmpty()) { if (this.isEmpty()) {
throw new Error('Queue is Empty') throw new Error('Queue is Empty')
} }
@ -66,7 +66,7 @@ class Queue {
* @description - Return the item at the front of the queue * @description - Return the item at the front of the queue
* @returns {*} * @returns {*}
*/ */
peekFirst () { peekFirst() {
if (this.isEmpty()) { if (this.isEmpty()) {
throw new Error('Queue is Empty') throw new Error('Queue is Empty')
} }
@ -78,7 +78,7 @@ class Queue {
* @description - Return the item at the tail of the queue * @description - Return the item at the tail of the queue
* @returns {*} * @returns {*}
*/ */
peekLast () { peekLast() {
if (this.isEmpty()) { if (this.isEmpty()) {
throw new Error('Queue is Empty') throw new Error('Queue is Empty')
} }
@ -90,7 +90,7 @@ class Queue {
* @description - Return the array of Queue * @description - Return the array of Queue
* @returns {Array<*>} * @returns {Array<*>}
*/ */
toArray () { toArray() {
const array = [] const array = []
let node = this.head let node = this.head
@ -106,7 +106,7 @@ class Queue {
* @description - Return is queue empty or not * @description - Return is queue empty or not
* @returns {boolean} * @returns {boolean}
*/ */
isEmpty () { isEmpty() {
return this.length === 0 return this.length === 0
} }
} }

View File

@ -2,17 +2,17 @@
// contribution made by hamza chabchoub for a university project // contribution made by hamza chabchoub for a university project
class Queue { class Queue {
constructor () { constructor() {
this.inputStack = [] this.inputStack = []
this.outputStack = [] this.outputStack = []
} }
// Push item into the inputstack // Push item into the inputstack
enqueue (item) { enqueue(item) {
this.inputStack.push(item) this.inputStack.push(item)
} }
dequeue () { dequeue() {
// push all items to outputstack // push all items to outputstack
this.outputStack = [] this.outputStack = []
while (this.inputStack.length > 0) { while (this.inputStack.length > 0) {
@ -31,7 +31,7 @@ class Queue {
} }
// display elements of the inputstack // display elements of the inputstack
listIn (output = value => console.log(value)) { listIn(output = (value) => console.log(value)) {
let i = 0 let i = 0
while (i < this.inputStack.length) { while (i < this.inputStack.length) {
output(this.inputStack[i]) output(this.inputStack[i])
@ -40,7 +40,7 @@ class Queue {
} }
// display element of the outputstack // display element of the outputstack
listOut (output = value => console.log(value)) { listOut(output = (value) => console.log(value)) {
let i = 0 let i = 0
while (i < this.outputStack.length) { while (i < this.outputStack.length) {
output(this.outputStack[i]) output(this.outputStack[i])

View File

@ -1,15 +1,15 @@
/* Stack!! /* Stack!!
* A stack is exactly what it sounds like. An element gets added to the top of * A stack is exactly what it sounds like. An element gets added to the top of
* the stack and only the element on the top may be removed. This is an example * the stack and only the element on the top may be removed. This is an example
* of an array implementation of a Stack. So an element can only be added/removed * of an array implementation of a Stack. So an element can only be added/removed
* from the end of the array. * from the end of the array.
*/ */
// Functions: push, pop, peek, view, length // Functions: push, pop, peek, view, length
// Creates a stack constructor // Creates a stack constructor
const Stack = (function () { const Stack = (function () {
function Stack () { function Stack() {
// The top of the Stack // The top of the Stack
this.top = 0 this.top = 0
// The array representation of the stack // The array representation of the stack
@ -45,13 +45,13 @@ const Stack = (function () {
} }
// To see all the elements in the stack // To see all the elements in the stack
Stack.prototype.view = function (output = value => console.log(value)) { Stack.prototype.view = function (output = (value) => console.log(value)) {
for (let i = 0; i < this.top; i++) { for (let i = 0; i < this.top; i++) {
output(this.stack[i]) output(this.stack[i])
} }
} }
return Stack return Stack
}()) })()
export { Stack } export { Stack }

View File

@ -10,19 +10,19 @@
// Class declaration // Class declaration
class Stack { class Stack {
constructor () { constructor() {
this.stack = [] this.stack = []
this.top = 0 this.top = 0
} }
// Adds a value to the end of the Stack // Adds a value to the end of the Stack
push (newValue) { push(newValue) {
this.stack.push(newValue) this.stack.push(newValue)
this.top += 1 this.top += 1
} }
// Returns and removes the last element of the Stack // Returns and removes the last element of the Stack
pop () { pop() {
if (this.top !== 0) { if (this.top !== 0) {
this.top -= 1 this.top -= 1
return this.stack.pop() return this.stack.pop()
@ -31,17 +31,17 @@ class Stack {
} }
// Returns the number of elements in the Stack // Returns the number of elements in the Stack
get length () { get length() {
return this.top return this.top
} }
// Returns true if stack is empty, false otherwise // Returns true if stack is empty, false otherwise
get isEmpty () { get isEmpty() {
return this.top === 0 return this.top === 0
} }
// Returns the last element without removing it // Returns the last element without removing it
get last () { get last() {
if (this.top !== 0) { if (this.top !== 0) {
return this.stack[this.stack.length - 1] return this.stack[this.stack.length - 1]
} }
@ -49,7 +49,7 @@ class Stack {
} }
// Checks if an object is the instance os the Stack class // Checks if an object is the instance os the Stack class
static isStack (el) { static isStack(el) {
return el instanceof Stack return el instanceof Stack
} }
} }

View File

@ -13,9 +13,9 @@
* RETURN > 0 if a > b * RETURN > 0 if a > b
* MUST RETURN 0 if a == b * MUST RETURN 0 if a == b
*/ */
let utils; let utils
(function (_utils) { ;(function (_utils) {
function comparator () { function comparator() {
return function (v1, v2) { return function (v1, v2) {
if (v1 < v2) return -1 if (v1 < v2) return -1
if (v2 < v1) return 1 if (v2 < v1) return 1
@ -32,7 +32,7 @@ let utils;
* If no argument is sent it uses utils.comparator * If no argument is sent it uses utils.comparator
*/ */
const AVLTree = (function () { const AVLTree = (function () {
function _avl (comp) { function _avl(comp) {
/** @public comparator function */ /** @public comparator function */
this._comp = undefined this._comp = undefined
this._comp = comp !== undefined ? comp : utils.comparator() this._comp = comp !== undefined ? comp : utils.comparator()
@ -53,7 +53,9 @@ const AVLTree = (function () {
// get height of a node // get height of a node
const getHeight = function (node) { const getHeight = function (node) {
if (node == null) { return 0 } if (node == null) {
return 0
}
return node._height return node._height
} }
@ -64,12 +66,15 @@ const AVLTree = (function () {
// update height of a node based on children's heights // update height of a node based on children's heights
const updateHeight = function (node) { const updateHeight = function (node) {
if (node == null) { return } if (node == null) {
return
}
node._height = Math.max(getHeight(node._left), getHeight(node._right)) + 1 node._height = Math.max(getHeight(node._left), getHeight(node._right)) + 1
} }
// Helper: To check if the balanceFactor is valid // Helper: To check if the balanceFactor is valid
const isValidBalanceFactor = (balanceFactor) => [0, 1, -1].includes(balanceFactor) const isValidBalanceFactor = (balanceFactor) =>
[0, 1, -1].includes(balanceFactor)
// rotations of AVL Tree // rotations of AVL Tree
const leftRotate = function (node) { const leftRotate = function (node) {
@ -140,13 +145,18 @@ const AVLTree = (function () {
} }
updateHeight(root) updateHeight(root)
const balanceFactor = getHeightDifference(root) const balanceFactor = getHeightDifference(root)
return isValidBalanceFactor(balanceFactor) ? root : insertBalance(root, val, balanceFactor, tree) return isValidBalanceFactor(balanceFactor)
? root
: insertBalance(root, val, balanceFactor, tree)
} }
// delete am element // delete am element
const deleteElement = function (root, _val, tree) { const deleteElement = function (root, _val, tree) {
if (root == null) { return root } if (root == null) {
if (tree._comp(root._val, _val) === 0) { // key found case return root
}
if (tree._comp(root._val, _val) === 0) {
// key found case
if (root._left === null && root._right === null) { if (root._left === null && root._right === null) {
root = null root = null
tree.size-- tree.size--
@ -177,7 +187,9 @@ const AVLTree = (function () {
} }
// search tree for a element // search tree for a element
const searchAVLTree = function (root, val, tree) { const searchAVLTree = function (root, val, tree) {
if (root == null) { return null } if (root == null) {
return null
}
if (tree._comp(root._val, val) === 0) { if (tree._comp(root._val, val) === 0) {
return root return root
} }
@ -222,7 +234,7 @@ const AVLTree = (function () {
return prevSize !== this.size return prevSize !== this.size
} }
return _avl return _avl
}()) })()
/** /**
* A Code for Testing the AVLTree * A Code for Testing the AVLTree

View File

@ -1,19 +1,19 @@
/* Binary Search Tree!! /* Binary Search Tree!!
* *
* Nodes that will go on the Binary Tree. * Nodes that will go on the Binary Tree.
* They consist of the data in them, the node to the left, the node * They consist of the data in them, the node to the left, the node
* to the right, and the parent from which they came from. * to the right, and the parent from which they came from.
* *
* A binary tree is a data structure in which an element * A binary tree is a data structure in which an element
* has two successors(children). The left child is usually * has two successors(children). The left child is usually
* smaller than the parent, and the right child is usually * smaller than the parent, and the right child is usually
* bigger. * bigger.
*/ */
// class Node // class Node
const Node = (function Node () { const Node = (function Node() {
// Node in the tree // Node in the tree
function Node (val) { function Node(val) {
this.value = val this.value = val
this.left = null this.left = null
this.right = null this.right = null
@ -32,7 +32,7 @@ const Node = (function Node () {
} }
// Visit a node // Visit a node
Node.prototype.visit = function (output = value => console.log(value)) { Node.prototype.visit = function (output = (value) => console.log(value)) {
// Recursively go left // Recursively go left
if (this.left !== null) { if (this.left !== null) {
this.left.visit() this.left.visit()
@ -103,14 +103,14 @@ const Node = (function Node () {
} }
// returns the constructor // returns the constructor
return Node return Node
}()) })()
// class Tree // class Tree
const Tree = (function () { const Tree = (function () {
function Tree () { function Tree() {
// Just store the root // Just store the root
this.root = null this.root = null
}; }
// Inorder traversal // Inorder traversal
Tree.prototype.traverse = function () { Tree.prototype.traverse = function () {
@ -149,6 +149,6 @@ const Tree = (function () {
// returns the constructor // returns the constructor
return Tree return Tree
}()) })()
export { Tree } export { Tree }

View File

@ -13,7 +13,7 @@
class SegmentTree { class SegmentTree {
size size
tree tree
constructor (arr) { constructor(arr) {
// we define tree like this // we define tree like this
// tree[1] : root node of tree // tree[1] : root node of tree
// tree[i] : i'th node // tree[i] : i'th node
@ -28,7 +28,7 @@ class SegmentTree {
} }
// function to build the tree // function to build the tree
build (arr) { build(arr) {
const { size, tree } = this const { size, tree } = this
// insert leaf nodes in tree // insert leaf nodes in tree
// leaf nodes will start from index N // leaf nodes will start from index N
@ -45,7 +45,7 @@ class SegmentTree {
} }
} }
update (index, value) { update(index, value) {
const { size, tree } = this const { size, tree } = this
// only update values in the parents of the given node being changed. // only update values in the parents of the given node being changed.
@ -65,7 +65,7 @@ class SegmentTree {
} }
// interval [L,R) with left index(L) included and right (R) excluded. // interval [L,R) with left index(L) included and right (R) excluded.
query (left, right) { query(left, right) {
const { size, tree } = this const { size, tree } = this
// cause R is excluded, increase right for convenient // cause R is excluded, increase right for convenient
right++ right++

View File

@ -1,4 +1,4 @@
const TrieNode = function TrieNode (key, parent) { const TrieNode = function TrieNode(key, parent) {
this.key = key this.key = key
this.count = 0 this.count = 0
this.children = Object.create(null) this.children = Object.create(null)
@ -9,7 +9,7 @@ const TrieNode = function TrieNode (key, parent) {
} }
} }
function Trie () { function Trie() {
// create only root with null key and parent // create only root with null key and parent
this.root = new TrieNode(null, null) this.root = new TrieNode(null, null)
} }
@ -18,7 +18,9 @@ function Trie () {
Trie.findAllWords = function (root, word, output) { Trie.findAllWords = function (root, word, output) {
if (root === null) return if (root === null) return
if (root.count > 0) { if (root.count > 0) {
if (typeof output === 'object') { output.push({ word, count: root.count }) } if (typeof output === 'object') {
output.push({ word, count: root.count })
}
} }
let key let key
for (key in root.children) { for (key in root.children) {
@ -38,7 +40,9 @@ Trie.prototype.insert = function (word) {
const len = word.length const len = word.length
let i let i
for (i = 0; i < len; i++) { for (i = 0; i < len; i++) {
if (node.children[word.charAt(i)] === undefined) { node.children[word.charAt(i)] = new TrieNode(word.charAt(i), node) } if (node.children[word.charAt(i)] === undefined) {
node.children[word.charAt(i)] = new TrieNode(word.charAt(i), node)
}
node = node.children[word.charAt(i)] node = node.children[word.charAt(i)]
} }
node.count += 1 node.count += 1
@ -87,7 +91,11 @@ Trie.prototype.remove = function (word, count) {
// if the object forms some other objects prefix we don't delete it // if the object forms some other objects prefix we don't delete it
// For checking an empty object // For checking an empty object
// https://stackoverflow.com/questions/679915/how-do-i-test-for-an-empty-javascript-object // https://stackoverflow.com/questions/679915/how-do-i-test-for-an-empty-javascript-object
if (child.count <= 0 && (Object.keys(child.children).length && child.children.constructor === Object)) { if (
child.count <= 0 &&
Object.keys(child.children).length &&
child.children.constructor === Object
) {
child.parent.children[child.key] = undefined child.parent.children[child.key] = undefined
} }
} }

Some files were not shown because too many files have changed in this diff Show More