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,7 +15,7 @@ space complexity - O(n*m)
const minimumEditDistance = (word1, word2) => {
const n = word1.length
const m = word2.length
const dp = new Array(m + 1).fill(0).map(item => [])
const dp = new Array(m + 1).fill(0).map((item) => [])
/*
fill dp matrix with default values -

View File

@ -1,12 +1,12 @@
/*
* This algorithm accepts a month in the format mm/yyyy.
* And prints out the month's calendar.
* It uses an epoch of 1/1/1900, Monday.
*/
* This algorithm accepts a month in the format mm/yyyy.
* And prints out the month's calendar.
* It uses an epoch of 1/1/1900, Monday.
*/
import { isLeapYear } from '../Maths/LeapYear'
class Month {
constructor () {
constructor() {
this.Days = ['M', 'T', 'W', 'Th', 'F', 'S', 'Su']
this.BDays = ['M', 'Su', 'S', 'F', 'Th', 'W', 'T']
this.epoch = { month: 1, year: 1900 }
@ -14,9 +14,10 @@ class Month {
this.monthDaysLeap = [31, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
}
printCal (days, startDay, output = value => console.log(value)) {
printCal(days, startDay, output = (value) => console.log(value)) {
output('M T W Th F S Su')
const dates = []; let i
const dates = []
let i
for (i = 1; i <= days; i++) {
dates.push(i)
}
@ -25,9 +26,9 @@ class Month {
}
while (true) {
let row = ''
for (i = 0; (i < 7) && (dates.length !== 0); i++) {
for (i = 0; i < 7 && dates.length !== 0; i++) {
row += dates.shift()
while ((row.length % 4) !== 0) {
while (row.length % 4 !== 0) {
row += ' '
}
}
@ -36,8 +37,10 @@ class Month {
}
}
parseDate (date) {
const dateAr = []; let block = ''; let i
parseDate(date) {
const dateAr = []
let block = ''
let i
for (i = 0; i < date.length; i++) {
if (date[i] === '/') {
dateAr.push(parseInt(block))
@ -52,7 +55,7 @@ class Month {
return dateOb
}
isGreater (startDate, endDate) {
isGreater(startDate, endDate) {
if (startDate.year > endDate.year) {
return true
} else if (startDate.year < endDate.year) {
@ -65,26 +68,28 @@ class Month {
return true
}
getDayDiff (startDate, endDate) {
getDayDiff(startDate, endDate) {
if (this.isGreater(startDate, endDate) === null) {
return 0
} else if ((this.isGreater(startDate, endDate) === true)) {
} else if (this.isGreater(startDate, endDate) === true) {
const midDate = startDate
startDate = endDate
endDate = midDate
}
let diff = 0
while (startDate.year !== endDate.year) {
diff += (isLeapYear(startDate.year)) ? 366 : 365
diff += isLeapYear(startDate.year) ? 366 : 365
startDate.year = startDate.year + 1
}
while (startDate.month !== endDate.month) {
if (startDate.month < endDate.month) {
if (isLeapYear(startDate.year)) diff += this.monthDaysLeap[startDate.month]
if (isLeapYear(startDate.year))
diff += this.monthDaysLeap[startDate.month]
else diff += this.monthDays[startDate.month]
startDate.month = startDate.month + 1
} else {
if (isLeapYear(startDate.year)) diff -= this.monthDaysLeap[startDate.month - 1]
if (isLeapYear(startDate.year))
diff -= this.monthDaysLeap[startDate.month - 1]
else diff -= this.monthDays[startDate.month - 1]
startDate.month = startDate.month - 1
}
@ -92,14 +97,18 @@ class Month {
return diff
}
generateMonthCal (date) {
const Month = this.parseDate(date); let day = ''
generateMonthCal(date) {
const Month = this.parseDate(date)
let day = ''
let difference = this.getDayDiff(this.epoch, Month)
difference = difference % 7
let Month2 = this.parseDate(date)
day = (this.isGreater(Month2, this.epoch)) ? this.Days[difference] : this.BDays[difference]
day = this.isGreater(Month2, this.epoch)
? this.Days[difference]
: this.BDays[difference]
Month2 = this.parseDate(date)
if (isLeapYear(Month2.year)) this.printCal(this.monthDaysLeap[Month2.month], day)
if (isLeapYear(Month2.year))
this.printCal(this.monthDaysLeap[Month2.month], day)
else this.printCal(this.monthDays[Month2.month], day)
}
}

View File

@ -9,7 +9,7 @@
* Reference article :- https://www.geeksforgeeks.org/largest-sum-contiguous-subarray/
*/
export function kadaneAlgo (array) {
export function kadaneAlgo(array) {
let cumulativeSum = 0
let maxSum = Number.NEGATIVE_INFINITY // maxSum has the least possible value
for (let i = 0; i < array.length; i++) {

View File

@ -7,7 +7,7 @@
* @see [Levenshtein_distance](https://en.wikipedia.org/wiki/Levenshtein_distance)
*/
function minimum (a, b, c) {
function minimum(a, b, c) {
if (a < b && a < c) {
return a
} else if (b < a && b < c) {
@ -17,12 +17,12 @@ function minimum (a, b, c) {
}
}
function costOfSubstitution (x, y) {
function costOfSubstitution(x, y) {
return x === y ? 0 : 1
}
// Levenshtein distance between x and y
function calculateLevenshteinDp (x, y) {
function calculateLevenshteinDp(x, y) {
const dp = new Array(x.length + 1)
for (let i = 0; i < x.length + 1; i++) {
dp[i] = new Array(y.length + 1)
@ -35,7 +35,12 @@ function calculateLevenshteinDp (x, y) {
} else if (j === 0) {
dp[i][j] = i
} else {
dp[i][j] = minimum(dp[i - 1][j - 1] + costOfSubstitution(x.charAt(i - 1), y.charAt(j - 1)), dp[i - 1][j] + 1, dp[i][j - 1] + 1)
dp[i][j] = minimum(
dp[i - 1][j - 1] +
costOfSubstitution(x.charAt(i - 1), y.charAt(j - 1)),
dp[i - 1][j] + 1,
dp[i][j - 1] + 1
)
}
}
}

View File

@ -27,11 +27,12 @@ References:
* @param {string} str2 Input string #2
* @returns {number} Length of the longest common subsequence
*/
function longestCommonSubsequence (str1, str2) {
const memo = new Array(str1.length + 1).fill(null)
function longestCommonSubsequence(str1, str2) {
const memo = new Array(str1.length + 1)
.fill(null)
.map(() => new Array(str2.length + 1).fill(null))
function recursive (end1, end2) {
function recursive(end1, end2) {
if (end1 === -1 || end2 === -1) {
return 0
}

View File

@ -4,7 +4,7 @@
*/
// Return the length of the Longest Increasing Subsequence, given array x
function longestIncreasingSubsequence (x) {
function longestIncreasingSubsequence(x) {
const length = x.length
const dp = Array(length).fill(1)

View File

@ -9,7 +9,9 @@
export const longestPalindromeSubsequence = function (s) {
const n = s.length
const dp = new Array(n).fill(0).map(item => new Array(n).fill(0).map(item => 0))
const dp = new Array(n)
.fill(0)
.map((item) => new Array(n).fill(0).map((item) => 0))
// fill predefined for single character
for (let i = 0; i < n; i++) {

View File

@ -1,9 +1,9 @@
function maximumNonAdjacentSum (nums) {
function maximumNonAdjacentSum(nums) {
/*
* Find the maximum non-adjacent sum of the integers in the nums input list
* :param nums: Array of Numbers
* :return: The maximum non-adjacent sum
*/
* Find the maximum non-adjacent sum of the integers in the nums input list
* :param nums: Array of Numbers
* :return: The maximum non-adjacent sum
*/
if (nums.length < 0) return 0

View File

@ -5,7 +5,7 @@
* @param {number[]} arrayItems
* @returns number
*/
export function maxProductOfThree (arrayItems) {
export function maxProductOfThree(arrayItems) {
// if size is less than 3, no triplet exists
const n = arrayItems.length
if (n < 3) throw new Error('Triplet cannot exist with the given array')

View File

@ -20,7 +20,9 @@ const minCostPath = (matrix) => {
for (let i = 1; i < n; i++) moves[i][0] = moves[i - 1][0] + matrix[i][0]
for (let i = 1; i < n; i++) {
for (let j = 1; j < m; j++) { moves[i][j] = Math.min(moves[i - 1][j], moves[i][j - 1]) + matrix[i][j] }
for (let j = 1; j < m; j++) {
moves[i][j] = Math.min(moves[i - 1][j], moves[i][j - 1]) + matrix[i][j]
}
}
return moves[n - 1][m - 1]

View File

@ -6,7 +6,7 @@ equal to the given sum.
/*
Given solution is O(n*sum) Time complexity and O(sum) Space complexity
*/
function NumberOfSubsetSum (array, sum) {
function NumberOfSubsetSum(array, sum) {
const dp = [] // create an dp array where dp[i] denote number of subset with sum equal to i
for (let i = 1; i <= sum; i++) {
dp[i] = 0

View File

@ -1,15 +1,17 @@
/*
* You are given a rod of 'n' length and an array of prices associated with all the lengths less than 'n'.
* Find the maximum profit possible by cutting the rod and selling the pieces.
*/
* You are given a rod of 'n' length and an array of prices associated with all the lengths less than 'n'.
* Find the maximum profit possible by cutting the rod and selling the pieces.
*/
export function rodCut (prices, n) {
export function rodCut(prices, n) {
const memo = new Array(n + 1)
memo[0] = 0
for (let i = 1; i <= n; i++) {
let maxVal = Number.MIN_VALUE
for (let j = 0; j < i; j++) { maxVal = Math.max(maxVal, prices[j] + memo[i - j - 1]) }
for (let j = 0; j < i; j++) {
maxVal = Math.max(maxVal, prices[j] + memo[i - j - 1])
}
memo[i] = maxVal
}

View File

@ -3,7 +3,7 @@ Given a data set of an unknown size,
Get a random sample in a random order
It's used in data analytics, often as a way to get a small random sample from a data lake or warehouse, or from a large CSV file
*/
function shuf (datasetSource, sampleSize) {
function shuf(datasetSource, sampleSize) {
const output = fillBaseSample(datasetSource, sampleSize)
return randomizeOutputFromDataset(datasetSource, output)
@ -16,7 +16,7 @@ function shuf (datasetSource, sampleSize) {
* @returns {Array.<T>} The random sample, as an array
* @template T
*/
function fillBaseSample (datasetSource, sampleSize) {
function fillBaseSample(datasetSource, sampleSize) {
let filledIndexes = []
let output = new Array(sampleSize)
@ -58,7 +58,7 @@ function fillBaseSample (datasetSource, sampleSize) {
* @returns {Array.<T>} The random sample, as an array
* @template T
*/
function randomizeOutputFromDataset (datasetSource, output) {
function randomizeOutputFromDataset(datasetSource, output) {
const newOutput = [...output]
let readSoFar = output.length
@ -82,8 +82,8 @@ function randomizeOutputFromDataset (datasetSource, output) {
* Generates a random range of data, with values between 0 and 2^31 - 1
* @param {number} length The number of data items to generate
* @returns {Iterable<number>} Random iterable data
*/
function * generateRandomData (length) {
*/
function* generateRandomData(length) {
const maxValue = Math.pow(2, 31) - 1
for (let i = 0; i < length; i++) {
yield Math.floor(Math.random() * maxValue)

View File

@ -5,7 +5,7 @@
* @return {Number[]} List of Primes till n.
* @see [Sieve_of_Eratosthenes](https://www.geeksforgeeks.org/sieve-of-eratosthenes/)
*/
function sieveOfEratosthenes (n) {
function sieveOfEratosthenes(n) {
if (n <= 1) return []
const primes = new Array(n + 1).fill(true) // set all as true initially
primes[0] = primes[1] = false // Handling case for 0 and 1

View File

@ -10,7 +10,7 @@
* @description Get the length of the longest substring without repeating characters
* @param {String} s - The input string
*/
export function LongestSubstringWithoutRepeatingCharacters (s) {
export function LongestSubstringWithoutRepeatingCharacters(s) {
let maxLength = 0
let start = 0
let end = 0

View File

@ -12,7 +12,7 @@
* @return {boolean} - Returns true if s2 contains a permutation of s1, or false otherwise.
*/
export function PermutationinString (s1, s2) {
export function PermutationinString(s1, s2) {
if (s1.length > s2.length) return false
let start = 0
let end = s1.length - 1
@ -35,11 +35,11 @@ export function PermutationinString (s1, s2) {
}
return false
}
function equals (a, b) {
function equals(a, b) {
return JSON.stringify(a) === JSON.stringify(b)
}
function SetHash () {
function SetHash() {
const set = new Set()
const alphabets = 'abcdefghijklmnopqrstuvwxyz'
for (let i = 0; i < alphabets.length; i++) {

View File

@ -1,7 +1,7 @@
const isValid = (board, row, col, k) => {
for (let i = 0; i < 9; i++) {
const m = 3 * Math.floor(row / 3) + Math.floor(i / 3)
const n = 3 * Math.floor(col / 3) + i % 3
const n = 3 * Math.floor(col / 3) + (i % 3)
if (board[row][i] === k || board[i][col] === k || board[m][n] === k) {
return false
}

View File

@ -12,7 +12,10 @@ const zeroOneKnapsack = (arr, n, cap, cache) => {
return cache[n][cap]
}
if (arr[n - 1][0] <= cap) {
cache[n][cap] = Math.max(arr[n - 1][1] + zeroOneKnapsack(arr, n - 1, cap - arr[n - 1][0], cache), zeroOneKnapsack(arr, n - 1, cap, cache))
cache[n][cap] = Math.max(
arr[n - 1][1] + zeroOneKnapsack(arr, n - 1, cap - arr[n - 1][0], cache),
zeroOneKnapsack(arr, n - 1, cap, cache)
)
return cache[n][cap]
} else {
cache[n][cap] = zeroOneKnapsack(arr, n - 1, cap, cache)
@ -52,9 +55,7 @@ const example = () => {
arr.push(input[j])
j++
}
const newArr = arr.map(e =>
e.trim().split(' ').map(Number)
)
const newArr = arr.map((e) => e.trim().split(' ').map(Number))
const cache = []
for (let i = 0; i <= currlen; i++) {
const temp = []

View File

@ -1,22 +1,22 @@
import { minimumEditDistance } from '../EditDistance'
test('minimumEditDistance(kitten, sitten) => 1', () => {
const str1 = 'kitten'
const str2 = 'sitten'
const res = minimumEditDistance(str1, str2)
expect(res).toEqual(1)
})
test('minimumEditDistance(school, skull) => 4', () => {
const str1 = 'school'
const str2 = 'skull'
const res = minimumEditDistance(str1, str2)
expect(res).toEqual(4)
})
test('minimumEditDistance(Algorithm, Algorithm) => 0', () => {
const str1 = 'Algorithm'
const str2 = 'Algorithm'
const res = minimumEditDistance(str1, str2)
expect(res).toEqual(0)
})
import { minimumEditDistance } from '../EditDistance'
test('minimumEditDistance(kitten, sitten) => 1', () => {
const str1 = 'kitten'
const str2 = 'sitten'
const res = minimumEditDistance(str1, str2)
expect(res).toEqual(1)
})
test('minimumEditDistance(school, skull) => 4', () => {
const str1 = 'school'
const str2 = 'skull'
const res = minimumEditDistance(str1, str2)
expect(res).toEqual(4)
})
test('minimumEditDistance(Algorithm, Algorithm) => 0', () => {
const str1 = 'Algorithm'
const str2 = 'Algorithm'
const res = minimumEditDistance(str1, str2)
expect(res).toEqual(0)
})

View File

@ -26,7 +26,11 @@ describe('LongestCommonSubsequence', () => {
})
it('expects to return the longest common subsequence, medium-length inputs', () => {
expect(longestCommonSubsequence('bsbininm', 'jmjkbkjkv')).toEqual('b'.length)
expect(longestCommonSubsequence('oxcpqrsvwf', 'shmtulqrypy')).toEqual('qr'.length)
expect(longestCommonSubsequence('bsbininm', 'jmjkbkjkv')).toEqual(
'b'.length
)
expect(longestCommonSubsequence('oxcpqrsvwf', 'shmtulqrypy')).toEqual(
'qr'.length
)
})
})

View File

@ -21,7 +21,7 @@ describe('MaxProductOfThree', () => {
describe('MaxProductOfThree, random arrays of size 3 to 5', () => {
// Slower function that operates in O(n^3), where n is the length of the input array.
// Calculates all possible products of 3 numbers in the array and returns the largest
function completeMaxThree (array) {
function completeMaxThree(array) {
let maximumProduct = null
for (let i = 0; i < array.length - 2; i++) {
for (let j = i + 1; j < array.length - 1; j++) {
@ -47,7 +47,9 @@ describe('MaxProductOfThree, random arrays of size 3 to 5', () => {
for (let i = 0; i < numberOfRandomTests; i++) {
const arr = []
// Randomize the length of the array in the current test
const length = Math.floor(Math.random() * (maxLength - minLength) + minLength)
const length = Math.floor(
Math.random() * (maxLength - minLength) + minLength
)
// Fill the array with random values in the specified range
for (let j = 0; j < length + 1; j++) {
@ -58,13 +60,19 @@ describe('MaxProductOfThree, random arrays of size 3 to 5', () => {
const expectedProduct = completeMaxThree(arr)
// Set up the expectation
it('Expect the array ' + arr.toString() + ' to return the maximum three product of ' + expectedProduct, () => {
// Calculate the max three product using the function being tested
const actualProduct = maxProductOfThree(arr)
it(
'Expect the array ' +
arr.toString() +
' to return the maximum three product of ' +
expectedProduct,
() => {
// Calculate the max three product using the function being tested
const actualProduct = maxProductOfThree(arr)
// Was unable to use expect().toBe(), since it sometimes compared 0 to -0, and that would not pass
// At the same time, standardjs forbid me from checking for === -0 to convert to 0
expect(actualProduct === expectedProduct).toBeTruthy()
})
// Was unable to use expect().toBe(), since it sometimes compared 0 to -0, and that would not pass
// At the same time, standardjs forbid me from checking for === -0 to convert to 0
expect(actualProduct === expectedProduct).toBeTruthy()
}
)
}
})

View File

@ -18,6 +18,8 @@ describe('SieveOfEratosthenes', () => {
})
it('Primes till 70', () => {
expect(sieveOfEratosthenes(70)).toEqual([2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67])
expect(sieveOfEratosthenes(70)).toEqual([
2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67
])
})
})

View File

@ -3,13 +3,37 @@ import { uniquePaths2 } from '../UniquePaths2'
describe('Unique Paths2', () => {
// Should return number of ways, taken into account the obstacles
test('There are obstacles in the way', () => {
expect(uniquePaths2([[0, 0, 0], [0, 1, 0], [0, 0, 0]])).toEqual(2)
expect(uniquePaths2([[0, 0, 0], [0, 1, 0], [0, 0, 0], [1, 0, 0]])).toEqual(3)
expect(
uniquePaths2([
[0, 0, 0],
[0, 1, 0],
[0, 0, 0]
])
).toEqual(2)
expect(
uniquePaths2([
[0, 0, 0],
[0, 1, 0],
[0, 0, 0],
[1, 0, 0]
])
).toEqual(3)
})
// Should return number of all possible ways to reach right-bottom corner
test('There are no obstacles in the way', () => {
expect(uniquePaths2([[0, 0, 0], [0, 0, 0], [0, 0, 0]])).toEqual(6)
expect(uniquePaths2([[0, 0, 0], [0, 0, 0]])).toEqual(3)
expect(
uniquePaths2([
[0, 0, 0],
[0, 0, 0],
[0, 0, 0]
])
).toEqual(6)
expect(
uniquePaths2([
[0, 0, 0],
[0, 0, 0]
])
).toEqual(3)
})
// Should throw an exception b/c input data has wrong type
test('There are wrong type of input data', () => {

View File

@ -2,11 +2,36 @@ import { zeroOneKnapsack } from '../ZeroOneKnapsack'
describe('ZeroOneKnapsack', () => {
it('zeroOneKnapsack when capacity is 4 and 5 items', () => {
expect(zeroOneKnapsack([[1, 8], [2, 4], [3, 0], [2, 5], [2, 3]], 5, 4, [[-1, -1, -1, -1, -1], [-1, -1, -1, -1, -1], [-1, -1, -1, -1, -1], [-1, -1, -1, -1, -1], [-1, -1, -1, -1, -1], [-1, -1, -1, -1, -1]])).toBe(13)
expect(
zeroOneKnapsack(
[
[1, 8],
[2, 4],
[3, 0],
[2, 5],
[2, 3]
],
5,
4,
[
[-1, -1, -1, -1, -1],
[-1, -1, -1, -1, -1],
[-1, -1, -1, -1, -1],
[-1, -1, -1, -1, -1],
[-1, -1, -1, -1, -1],
[-1, -1, -1, -1, -1]
]
)
).toBe(13)
})
it('zeroOneKnapsack when capacity is 1 and 1 items', () => {
expect(zeroOneKnapsack([[1, 80]], 1, 1, [[-1, -1], [-1, -1]])).toBe(80)
expect(
zeroOneKnapsack([[1, 80]], 1, 1, [
[-1, -1],
[-1, -1]
])
).toBe(80)
})
it('zeroOneKnapsack when capacity is 0 and 1 items', () => {