Arrow Function of JavaScript question - Multiple Arrow Function nesting - javascript

I saw a answer when I am practicing JS on leetcode, but I can't understand what this mean. can anyone expand the code? or tell me how to read this.
https://leetcode.com/problems/running-sum-of-1d-array/discuss/702025/one-liner
let runningSum = nums => nums.map((sum => el => sum += el)(0));
console.log(runningSum([1,2,3,4]))

Original function
let runningSum = nums => nums.map((sum => el => sum += el)(0));
(sum => el => sum += el) is
function f1(sum) {
return function f2(el) {
return sum += el;
}
}
(or in arrow format as shown by #Alterlife)
The original function then transforms into
let runningSum = nums => nums.map(f1(0));
then nums.map(f1(0));
becomes
const result = [];
const f2 = f1(0);
for(let i = 0; i < nums.length; ++i) {
const num = nums[i];
result.push(f2(num));
}
So all together, the original function transforms into
const nums = [1,2,3,4];
function f1(sum) {
return function f2(el) {
return sum += el;
}
}
const result = [];
const f2 = f1(0);
for(let i = 0; i < nums.length; ++i) {
const num = nums[i];
result.push(f2(num));
}
console.log(result);

Let's try and break it down.
(sum => el => sum += el) , is equivalent to:
const mySumFunction = (sum) => {
const addToSum = (el) => {
sum += el;
return sum;
}
return addToSum;
}
This is a function that takes in a parameter - a starting sum. The sum parameter is also local variable within the function's scope.
When you call mySumFunction, it returns another function that adds to the local scoped variable sum and returns the total sum so far.
In effect, it creates a "function with memory" that returns the sum of everything that has been passed into it so far.
You can test this out as follows:
cumilativeSum = mySumFunction(0)
console.log(v(1)) // returns 1
console.log(v(1)) // returns 2
console.log(v(4)) // returns 6
Now let's look at the code as a whole.
let runningSum = nums => nums.map((sum => el => sum += el)(0));
The entire snippet passed into the map function: (sum => el => sum += el)(0) creates a "sum function with memory" that starts at 0, as we figured out above.
We're passing each of the numbers in an array to it and creating an array with the cumulative sum.

Let's take (sum => el => sum += el)(0) this self invocation arrow function for 1st iteration of map. Up on execution it return another arrow function el => sum += el. The value of sum is 0 which is passed as argument. Now keep come to our map 1st iteration
let runningSum = nums => nums.map(el => sum = 0 + el);
It returns 1. So, for the 2nd iteration, the value of the sum is 1 and el is 2.
so it returns 3, then 6 and then 10.
let runningSum = (nums) =>
nums.map(
(function (sum) {
return (el) => (sum += el);
})(0)
);
console.log(runningSum([1, 2, 3, 4]));

Related

Is there a way to make this Javascript code more efficient?

It is a simple exercise that I am doing for mere practice and leisure, I have done it in various ways but I was wondering if there is an even more practical way or to reduce the lines of code making use of the many methods of JavaScript.
The exercise is about receiving an array (arr) and a number (target) and returning another array with a pair of numbers found in 'arr' whose sum is equal to 'target'.
function targetSum3(arr, target) {
let newArr = [];
let copyArray = arr;
for (let i of copyArray) {
let x = Math.abs(i - target);
copyArray.pop(copyArray[i]);
if (copyArray.includes(x) && (copyArray.indexOf(x) != copyArray.indexOf(i))) {
newArr.push(i);
newArr.push(x);
return newArr;
}
}
return newArr;
}
If you are fine with a function that just returns a pair of numbers (the first match so to speak) whose sum equals the targets value, this might be enough:
function sumPair (arr, target) {
while(arr.length) {
let sum1 = arr.shift();
let sum2 = arr.find(val => sum1 + val === target);
if (sum2) return [sum2, sum1];
}
return null;
}
const targetSum = (arr, target) => {
const first = arr.find((v,i,a) => arr.includes(target-v) && (arr.indexOf(target-v) !== i));
return first ? [first, target - first] : null;
};
const values = [1,2,3,4,5,6,7,8,9];
console.log(targetSum(values, 1)); // null
console.log(targetSum(values, 2)); // null
console.log(targetSum(values, 3)); // [1, 2]
console.log(targetSum(values, 15)); // [6, 9]
console.log(targetSum(values, 20)); // null
I changed for loop with forEach (more efficient) and there is no need for the copyArray array so I removed it. I also changed pop() with shift(), I think you want to shift the array and not pop-it (if I understand the task correctly).
function targetSum3(arr, target) {
let newArr = [];
arr.forEach(element => {
let x = Math.abs(element - target); // calc x
arr.shift(); // removes first element from arr (current element)
if (arr.includes(x) && (arr.indexOf(x) != arr.indexOf(element))) {
newArr.push(element);
newArr.push(x);
return;
}
});
return newArr;
}
use Array.filter to find the target sum for all values in an given array. See comments in the snippet.
sumsForTargetInArray();
document.addEventListener(`click`,
evt => evt.target.id === `redo` && sumsForTargetInArray());
function sumsInArray(arr, target) {
// clone the array
const clone = arr.slice();
let result = [];
while (clone.length) {
// retrieve the current value (shifting it from the clone)
const current = clone.shift();
// filter arr: all values where value + sum = target
const isTarget = arr.filter(v => current + v === target);
// add to result.
// Sorting is to prevent duplicates later
if (isTarget.length) {
result = [...result, ...isTarget.map(v => [current, v].sort())];
}
}
// weed out duplicates (e.g. 0 + 3, 3 + 0)
const unique = new Set();
result.forEach(r => unique.add(`${r[0]},${r[1]}`));
// return array of array(2)
return [...unique].map(v => v.split(`,`).map(Number));
}
function sumsForTargetInArray() {
const testArr = [...Array(20)].map((_, i) => i);
const target = Math.floor(Math.random() * 30);
document.querySelector(`pre`).textContent = `testArray: ${
JSON.stringify(testArr)}\ntarget: ${target}\nResult: ${
JSON.stringify(sumsInArray(testArr, target))}`;
}
<pre></pre>
<button id="redo">Again</button>

Find how many items in array are greater equal or less than given number Javascript

let numbers = [2, 2, 6, 10];
const findAvarage = (numbers) => {
let total = 0;
let checkIntegers = numbers.every(i => !Number.isInteger(i))
if (checkIntegers = true) {
for(let i = 0; i < numbers.length; i++) {
total += numbers[i];
}
let avg = total / numbers.length;
return avg
} else {
return "Only integers allowed"
}
const compareNumbers = (numbers) => {
}
In this code I calculate the avarage of the given numbers in array and now I want to find how many numbers in array are greater that avarage number with second function
I tried to use find method but it did not work out,any solutions on this please?
You can use filter function to filter out the numbers that are larger than average.
const avg = findAvarage(numbers)
const count = numbers.filter(number => number > avg).length
const compareNumbers = (numbers) => {
const avg = findAvarage(numbers);
let greater = 0;
numbers.forEach((num) => { if (num > avg) greater++; });
return greater;
}
u can use filter or reduce to solve it
let numbers = [2, 2, 6, 10];
function countNumbers(number){
return numbers.filter(num=> num>=number).length;
}
function countNumbers2(number){
return numbers.reduce((count,item)=>count+(item>=number),0)
}
console.log(countNumbers(7));
console.log(countNumbers2(3))
Javascript does not provide many extension methods that can be used for arrays, you have just some basics operations.
Your code can be more cleaner if you turn this need into extensions for arrays that you can them every where without calling functions, you can do as follow:
Object.defineProperties(Array.prototype, {
count: {
value: function(value) {
if(isNan(value)) return NaN;
return this.filter(x => x>=value).length;
}
},
average:{
value:function(){
let total = 0;
if(!this.every(i => Number.isInteger(i)))
return NaN;
for(let i = 0; i < numbers.length; i++) {
total += numbers[i];
}
return total/this.length;
}
}
});
and you can use it like this for you example
var result = numbers.count(numbers.average())
this way ?
const findAvarage=(a,b,c,d) => [a,b,c,d].reduceRight((t,n,i,a)=>
{
t += n
if (!i) t /= a.length
return t
},0)
, greaterOrEqualCount = (a,b,c,d) =>
{
let avg = findAvarage(a,b,c,d)
return [a,b,c,d].reduce((r,n)=>r+(n<avg?0:1),0)
}
console.log("count ",greaterOrEqualCount(2,2,6,10))

JavaScript returning ObjectObject with no fields returning as expected { a: 2, b: 2, c: 1 }

I am constructing a reduce function that accepts an array, a callback, and an initial value and returns a single value. The function satisfies 2/3 of the following conditions: should not mutate the input array, should sum up an array, and should create a "totals" object from an array.
function reduce(array, callback, num) {
let sum = 0;
let totals;
for ( let i = 0; i < array.length; i++) {
sum += num + array[i];
}
return sum
array.forEach(function(ele, index){
totals = callback(totals, ele);
});
return totals;
}
I've satisfied all these conditions except the final one. I get the following error after running my code where my reduce function fails to "create a "totals" object from an array":
expected 'expected
'0[object Object]a[object Object]b[object Object]c[object Object]a[object Object]b'
to deeply equal
{ a: 2, b: 2, c: 1 }.
Any input here would be appreciated.
First, the return keyword ends the function. So, writing any code past that return sum would have no effect at all. And in fact, you don't need that return, nor the loop above it:
function reduce(array, callback, totals) {
// By default, if totals is empty, reduce uses the first element as a base
if (typeof totals === "undefined" && array.length > 0) {
totals = array[0];
array = array.slice(1);
}
array.forEach(function(ele, index){
totals = callback(totals, ele);
});
return totals;
}
console.log( reduce([1, 2, 3], (sum, v) => sum + v) ); // 6
console.log( reduce([1, 2, 3], (sum, v) => sum + v, 3) ); // 9
Sorry but your code makes no sense. Here's why:
function reduce(array, callback, num) {
let sum = 0;
let totals;
// Problem one - you are hardcoding behaviour instead of
// using a callback which is normally supposed to inject the reducing logics
for ( let i = 0; i < array.length; i++) {
sum += num + array[i];
}
return sum // after that line all the code is a deadcode
// as the return command terminates your reduce function
// and returns sum
array.forEach(function(ele, index){
totals = callback(totals, ele);
// as I said this is the dead code. Anyways pay attention that
// totals variable is instantiated but undefined. What are you planning
// to achieve by providing it to the callback function?
});
return totals;
}
And here's my implementation of the standard JS API Array.prototype.reduce function:
function myReduce (cb, initialValue) {
if (!Array.isArray(this) || (!this.length && !initialValue))
throw TypeError;
// making a copy of the original array to prevent
// it from being mutated by a callback
const array = [...this];
// if no initial value is provided, we take the first element
// of array instead
let acc = initialValue || array[0];
// if no initialValue is provided we start iteration from 1
// else the iterations starts from 0
for (let i = Number(!initialValue); i < array.length; i++)
acc = cb (acc, array[i], i, array);
return acc;
}
// here's what you supposedly are trying to achieve:
const myArray = [1,2,3,4,5];
// hereinafter I will use Function.prototype.call
// to bind the array to myReduce function
console.log(myReduce.call(myArray, (acc, cur) => acc + cur)); // => 15
// And more advanced example of a simple array-to-object mapper:
const myArray2 = [
{id: 0, email: 'user0#co.cc'},
{id: 1, email: 'user1#co.cc'},
{id: 2, email: 'user2#co.cc'},
];
console.log(myReduce.call(
myArray2, // this
(acc, {email, id}) => ({...acc, [id]: email}), // cb
{} // initial state
)); // => Object {0: "user0#co.cc", 1: "user1#co.cc", 2: "user2#co.cc"}
Hopefully that will be helpful. Good luck!

Getting sum using += doesn't work in here. Why?

I'm trying to return true or false if given value is narcissistic number.
After assigned empty variable sum, then try to getting sum using +=
But, I don't know It doesn't work in here.
function narcissistic(n) {
let arr = Array.from(String(n), Number);
// ex) 999 => [9,9,9]
let sum;
arr.forEach((e) => {
sum += Math.pow(e,arr.length) ;
})
return sum === n ? true: false
}
It results in NaN. Have no idea why?
So I had to use this one and It works.
function narcissistic(n) {
let arr = Array.from(String(n), Number);
// ex) 999 => [9,9,9]
let newArr = [];
arr.forEach((e) => {
newArr.push(Math.pow(e,arr.length)) ;
})
let sum = newArr.reduce((a,b) => a+b);
return sum === n ? true: false
}
So my question is why the first one doesn't work when it comes to sum += ??
You need to make sum equal to 0 - it starts out life as undefined, and any mathematics with undefined leads to NaN.
let sum = 0;
This should fix your problem.
A more concise way to do this is with reduce:
let sum = arr.reduce((a, c) => a + Math.pow(c, arr.length));
We should initialize your variable before referencing.
let sum = 0;
It could solve your issue.

What is the best way to sum arrays using ECMASCRIPT 6 Generator/Functions

Is there a better way instead of adding values of arrays up using a generator function as closure?
var sumArrays = function(){
var sum = 0;
return function*(){
while(true){
var array = yield sum;
if(array.__proto__.constructor === Array){
sum += array.reduce(function(val,val2){ return val+val2; });
}
else sum=0;
}
};
};
var gen = sumArrays();
// is this step required to make a generator or could it be done at least differently to spare yourself from doing this step?
gen = gen();
// sum some values of arrays up
console.log('sum: ',gen.next()); // Object { value=0, done=false}
console.log('sum: ',gen.next([1,2,3,4])); // Object { value=10, done=false}
console.log('sum: ',gen.next([6,7])); // Object { value=23, done=false}
// reset values
console.log('sum: ',gen.next(false)); // Object { value=0, done=false}
console.log('sum: ',gen.next([5])); // Object { value=5, done=false}
This doesn't seem to be a problem generators are supposed to solve, so I would not use a generator here.
Directly using reduce (ES5) seems to be more appropriate:
let sum = [1,2,3,4].reduce((sum, x) => sum + x);
As a function:
function sum(arr) {
return arr.reduce((sum, x) => sum + x);
}
If you really want to sum multiple arrays across multiple function calls, then return a normal function:
function getArraySummation() {
let total = 0;
let reducer = (sum, x) => sum + x;
return arr => total + arr.reduce(reducer);
}
let sum = getArraySummation();
console.log('sum:', sum([1,2,3])); // sum: 6
console.log('sum:', sum([4,5,6])); // sum: 15
Keep it simple.
Here is use of for/of loop and arrow function,
const sumArray = myArray => {
let sum = 0;
for(const value of myArray)
sum+= value;
return sum;
}
const myArray = [1, 2, 5];
console.log(sumArray(myArray));

Categories

Resources