30 Days of JavaScript on LeetCode
2667. Create Hello World Function
/**
* @return {Function}
*/
var createHelloWorld = function() {
return function(...args) {
return "Hello World"
}
};
/**
* const f = createHelloWorld();
* f(); // "Hello World"
*/
/**
* @param {number} n
* @return {Function} counter
*/
var createCounter = function(n) {
let counter = n;
return function() {
return counter++
};
};
/**
* const counter = createCounter(10)
* counter() // 10
* counter() // 11
* counter() // 12
*/
/**
* @param {string} val
* @return {Object}
*/
var expect = function(val) {
return {
toBe : (arg) => {
if (val === arg){
return true
}
throw "Not Equal"
},
notToBe : (arg) => {
if (val !== arg) {
return true
}
throw "Equal"
}
}
};
/**
* expect(5).toBe(5); // true
* expect(5).notToBe(5); // throws "Equal"
*/
/**
* @param {integer} init
* @return { increment: Function, decrement: Function, reset: Function }
*/
var original;
var createCounter = function(init) {
original = init
return {
increment: () => {
return init += 1
},
decrement: () => {
return init -= 1
},
reset: () => {
init = original
return init
}
}
};
/**
* const counter = createCounter(5)
* counter.increment(); // 6
* counter.reset(); // 5
* counter.decrement(); // 4
*/
2635. Apply Transform Over Each Element in Array
/**
* @param {number[]} arr
* @param {Function} fn
* @return {number[]}
*/
var map = function(arr, fn) {
for(let [i, ele] of arr.entries()) {
ele = fn(ele, i)
}
return arr
};
2634. Filter Elements from Array
/**
* @param {number[]} arr
* @param {Function} fn
* @return {number[]}
*/
var filter = function(arr, fn) {
const newArr = [];
for (let i = 0; i < arr.length; ++i) {
if (fn(arr[i], i)) {
newArr.push(arr[i]);
}
}
return newArr;
};
2626. Array Reduce Transformation
/**
* @param {number[]} nums
* @param {Function} fn
* @param {number} init
* @return {number}
*/
// var reduce = function(nums, fn, init) {
// let output = init;
// for(let i = 0; i < nums.length; i++) {
// output = fn(output, nums[i])
// }
// return output
// };
var reduce = function(arr, fn, initialVal) {
let accumulator = initialVal;
for (const element of arr) {
accumulator = fn(accumulator, element);
}
return accumulator;
};
/**
* @param {Function[]} functions
* @return {Function}
*/
var compose = function(functions) {
return function(x) {
let output = x
for(func of functions.reverse()){
output = func(output)
}
return output
}
};
/**
* const fn = compose([x => x + 1, x => 2 * x])
* fn(4) // 9
*/
2703. Return Length of Arguments Passed
/**
* @return {number}
*/
var argumentsLength = function(...args) {
return [...args].length
};
/**
* argumentsLength(1, 2, 3); // 3
*/
/**
* @param {Function} fn
* @return {Function}
*/
var once = function(fn) {
let called = false
return function(...args){
if(!called){
called = true
return fn(...args)
}
}
};
/**
* let fn = (a,b,c) => (a + b + c)
* let onceFn = once(fn)
*
* onceFn(1,2,3); // 6
* onceFn(2,3,6); // returns undefined without calling fn
*/
/**
* @param {Function} fn
*/
function memoize(fn) {
const cache = {}
return function(...args) {
const key = JSON.stringify(args)
if(key in cache){
return cache[key]
}
cache[key] = fn(...args)
return cache[key]
}
}
/**
* let callCount = 0;
* const memoizedFn = memoize(function (a, b) {
* callCount += 1;
* return a + b;
* })
* memoizedFn(2, 3) // 5
* memoizedFn(2, 3) // 5
* console.log(callCount) // 1
*/
/**
* @param {Promise} promise1
* @param {Promise} promise2
* @return {Promise}
*/
var addTwoPromises = async function(promise1, promise2) {
return promise1.then(a => {
return promise2.then(b => {
return a + b
})
})
};
/**
* addTwoPromises(Promise.resolve(2), Promise.resolve(2))
* .then(console.log); // 4
*/
/**
* @param {number} millis
*/
async function sleep(millis) {
return new Promise(resolve => setTimeout(resolve, millis));
}
/**
* let t = Date.now()
* sleep(100).then(() => console.log(Date.now() - t)) // 100
*/
/**
* @param {Function} fn
* @param {Array} args
* @param {number} t
* @return {Function}
*/
var cancellable = function(fn, args, t) {
const timer = setTimeout(fn, t, ...args)
return () => {
clearTimeout(timer)
}
};
/**
* const result = []
*
* const fn = (x) => x * 5
* const args = [2], t = 20, cancelT = 50
*
* const start = performance.now()
*
* const log = (...argsArr) => {
* const diff = Math.floor(performance.now() - start);
* result.push({"time": diff, "returned": fn(...argsArr))
* }
*
* const cancel = cancellable(log, args, t);
*
* const maxT = Math.max(t, cancelT)
*
* setTimeout(() => {
* cancel()
* }, cancelT)
*
* setTimeout(() => {
* console.log(result) // [{"time":20,"returned":10}]
* }, maxT + 15)
*/
/**
* @param {Function} fn
* @param {Array} args
* @param {number} t
* @return {Function}
*/
var cancellable = function(fn, args, t) {
fn(...args)
const timer = setInterval(fn, t, ...args)
return () => {
clearInterval(timer)
}
};
/**
* const result = []
*
* const fn = (x) => x * 2
* const args = [4], t = 20, cancelT = 110
*
* const start = performance.now()
*
* const log = (...argsArr) => {
* const diff = Math.floor(performance.now() - start)
* result.push({"time": diff, "returned": fn(...argsArr)})
* }
*
* const cancel = cancellable(log, args, t);
*
* setTimeout(() => {
* cancel()
* }, cancelT)
*
* setTimeout(() => {
* console.log(result) // [
* // {"time":0,"returned":8},
* // {"time":20,"returned":8},
* // {"time":40,"returned":8},
* // {"time":60,"returned":8},
* // {"time":80,"returned":8},
* // {"time":100,"returned":8}
* // ]
* }, cancelT + t + 15)
*/
/**
* @param {Function} fn
* @param {number} t
* @return {Function}
*/
var timeLimit = function(fn, t) {
return async function(...args) {
return new Promise((resolve, reject)=>{
setTimeout(()=>{
reject('Time Limit Exceeded')
}, t)
fn(...args).then((value)=>{
resolve(value)
}).catch((err)=>{
reject(err)
})
})
}
};
/**
* const limited = timeLimit((t) => new Promise(res => setTimeout(res, t)), 100);
* limited(150).catch(console.log) // "Time Limit Exceeded" at t=100ms
*/
var TimeLimitedCache = function() {
this.cache = {}
};
/**
* @param {number} key
* @param {number} value
* @param {number} duration time until expiration in ms
* @return {boolean} if un-expired key already existed
*/
TimeLimitedCache.prototype.set = function(key, value, duration) {
const currentTs = Date.now()
if (key in this.cache) {
const [prevVal, dur, ts] = this.cache[key]
if (ts + dur < currentTs){
}
this.cache[key] = [value, duration, currentTs]
return true
}
this.cache[key] = [value, duration, Date.now()]
return false
};
/**
* @param {number} key
* @return {number} value associated with key
*/
TimeLimitedCache.prototype.get = function(key) {
if(!(key in this.cache)) {
return -1
}
const [value, dur, ts] = this.cache[key]
const currentTs = Date.now()
if (ts + dur > currentTs){
return value
}
return -1
};
/**
* @return {number} count of non-expired keys
*/
TimeLimitedCache.prototype.count = function() {
let count = 0
Object.keys(this.cache).forEach((key)=>{
const [value, dur, ts] = this.cache[key]
const currentTs = Date.now()
if (ts + dur > currentTs){
count += 1
}
})
return count
};
/**
* Your TimeLimitedCache object will be instantiated and called as such:
* var obj = new TimeLimitedCache()
* obj.set(1, 42, 1000); // false
* obj.get(1) // 42
* obj.count() // 1
*/
/**
* @param {Function} fn
* @param {number} t milliseconds
* @return {Function}
*/
var debounce = function(fn, t) {
var timer = null
return function(...args) {
clearTimeout(timer)
timer = setTimeout(fn, t, ...args)
}
};
/**
* const log = debounce(console.log, 100);
* log('Hello'); // cancelled
* log('Hello'); // cancelled
* log('Hello'); // Logged at t=100ms
*/
2721. Execute Asynchronous Functions in Parallel
/**
* @param {Array<Function>} functions
* @return {Promise<any>}
*/
var promiseAll = async function(functions) {
return new Promise(async (resolve, reject) => {
if (functions.length === []){
resolve([])
return
}
// const res = new Array(functions.length).fill(null)
const res = []
for(const prom of functions) {
try {
const subRes = await prom()
res.push(subRes)
} catch(err) {
// Reject if any promise got rejected
reject(err)
}
}
// Resolve if all resolved
resolve(res)
})
};
/**
* const promise = promiseAll([() => new Promise(res => res(42))])
* promise.then(console.log); // [42]
*/
/**
* @param {Object | Array} obj
* @return {boolean}
*/
var isEmpty = function(obj) {
return Object.keys(obj).length === 0
};
/**
* @param {Array} arr
* @param {number} size
* @return {Array[]}
*/
var chunk = function(arr, size) {
l = arr.length
// find number of iterations needed
n = parseInt(l / size)
let ans = []
for(let i = 0; i < n; i++ ){
ans.push(arr.slice(i * size, (i * size) + size))
}
const m = l % size
if(m > 0) {
ans.push(arr.slice(-m))
}
return ans
};
Array.prototype.last = function() {
if (this.length > 0) {
return this[this.length - 1]
}
return -1
};
/**
* const arr = [1, 2, 3];
* arr.last(); // 3
*/
/**
* @param {Function} fn
* @return {Array}
*/
Array.prototype.groupBy = function(fn) {
const output = {}
this.forEach((x) => {
const key = fn(x)
if(key in output) {
output[key].push(x)
} else {
output[key] = [x]
}
})
return output
};
/**
* [1,2,3].groupBy(String) // {"1":[1],"2":[2],"3":[3]}
*/
/**
* @param {Array} arr
* @param {Function} fn
* @return {Array}
*/
var sortBy = function(arr, fn) {
return arr.sort((a, b) => {
return (fn(a) < fn(b)) ? -1 : 1;
});
};
/**
* @param {Array} arr1
* @param {Array} arr2
* @return {Array}
*/
var join = function(arr1, arr2) {
const data = {}
for(const ele of arr1){
data[ele.id] = ele
}
for(const ele of arr2){
if(ele.id in data){
data[ele.id] = Object.assign(data[ele.id], ele)
} else {
data[ele.id] = ele
}
}
return Object.values(data)
};
2625. Flatten Deeply Nested Array
/**
* @param {any[]} arr
* @param {number} depth
* @return {any[]}
*/
var flat = function (arr, n) {
const output = []
const rec = (arg, d) => {
for(const val of arg){
// Alternate 1 : typeof(val) === 'object'
// Alternate 2 : Array.isArray(val)
if(val instanceof Array && d < n){
rec(val, d + 1)
} else {
output.push(val)
}
}
return output
}
return rec(arr, 0)
};
/**
* @param {Object|Array} obj
* @return {Object|Array}
*/
var compactObject = function(obj) {
if(!obj) return false
if (typeof obj != 'object') return obj
let compactArr = []
if (obj instanceof Array){
for(const ele of obj){
const sub = compactObject(ele)
if (sub) {
compactArr.push(sub)
}
}
return compactArr
}
const compactObj = {}
for(const key in obj) {
const sub = compactObject(obj[key])
if(sub){
compactObj[key] = sub
}
}
return compactObj
};
class EventEmitter {
constructor() {
this.subscriptions = {}
}
subscribe(event, cb) {
console.log('check', typeof cb)
if (event in this.subscriptions) {
this.subscriptions[event].push(cb)
} else {
this.subscriptions[event] = [cb]
}
const index = this.subscriptions[event].length
return {
unsubscribe: () => {
this.subscriptions[event].splice(index - 1, 1)
return undefined
}
};
}
emit(event, args = []) {
const cb = this.subscriptions[event]
let output = []
if(cb){
for(const c of cb) {
output.push(c(...args))
}
}
return output
}
}
/**
* const emitter = new EventEmitter();
*
* // Subscribe to the onClick event with onClickCallback
* function onClickCallback() { return 99 }
* const sub = emitter.subscribe('onClick', onClickCallback);
*
* emitter.emit('onClick'); // [99]
* sub.unsubscribe(); // undefined
* emitter.emit('onClick'); // []
*/
/**
* @param {number[]} nums
*/
var ArrayWrapper = function(nums) {
this.nums = nums
};
ArrayWrapper.prototype.valueOf = function() {
let s = 0
this.nums.forEach(e => {
s += e
})
return s
}
ArrayWrapper.prototype.toString = function() {
return "["+this.nums.toString()+"]"
}
/**
* const obj1 = new ArrayWrapper([1,2]);
* const obj2 = new ArrayWrapper([3,4]);
* obj1 + obj2; // 10
* String(obj1); // "[1,2]"
* String(obj2); // "[3,4]"
*/
2726. Calculator with Method Chaining
class Calculator {
/**
* @param {number} value
*/
constructor(value) {
this.result = value
}
/**
* @param {number} value
* @return {Calculator}
*/
add(value){
this.result += value
return this
}
/**
* @param {number} value
* @return {Calculator}
*/
subtract(value){
this.result -= value
return this
}
/**
* @param {number} value
* @return {Calculator}
*/
multiply(value) {
this.result *= value
return this
}
/**
* @param {number} value
* @return {Calculator}
*/
divide(value) {
if (value == 0) {
throw "Division by zero is not allowed"
}
this.result /= value
return this
}
/**
* @param {number} value
* @return {Calculator}
*/
power(value) {
this.result = Math.pow(this.result, value);
return this
}
/**
* @return {number}
*/
getResult() {
return this.result
}
}