Reduce method not clear - javascript

So, I started playing with reduce() and I realised I can pass an Object as the first element of the method and I saw a couple of examples and this is one of them.
const arr = ['y', 'n', 'y', 'y', 'n'];
let test = arr2.reduce((sum, val) => {
sum[val] = (sum[val] || 0) + 1;
console.log('sum of val', sum[val], 'value', val)
return sum;
}, {})
I added that console log so I can see what is going on, but I cant figure it out. HOW DOES THE METHOD KNOW? How does it add that val (which is n or y) in the object and followed by it add the sum of how many of identical elements exists in the array. How does that sum become for example {y: 20} - assuming there are 20 y's in an array.
Im confused by it, at first it seemed simple but I guess its not.

It doesn't "know", you do it, here: sum[val] = (sum[val] || 0) + 1;
sum is the empty object in the first iteration, and then it's the one returned from the previous iteration (which is the same, due to return sum;). And val is the current value ('y' or 'n').
So, in the first iteration, sum will be {} and val will be 'y'. This line will then set sum['y'] = 1 because it essentially does sum['y'] = (sum['y'] || 0) + 1 - and sum['y'] is undefined at that point, so you'll have (undefined || 0) + 1 which is 0 + 1 which is 1.
The next time the same happens for 'n'.
And the third time, sum['y'] will be already 1 from before, so that expression becomes (1 || 0) + 1 which is 1 + 1 which is 2, so you get sum['y'] = 2.
And so on.
See this screencast from a debugger: https://recordit.co/FVkXjW1b5y

.reduce() takes two arguments
callback function
initial value (optional)
In your case, empty object literal {} is the initial value. If initial value is supplied, it is passed as the first argument to the callback function.
Second argument to the callback function of .reduce() is the current element of the array on which .reduce() is called. In first iteration, val is the first element in the arr array, i.e. 'y'.
sum[val] = (sum[val] || 0) + 1;
In each iteration, above statement will add value of val as a key in the sum object (initial value) and its value is 0 + 1 if sum[val] is undefined or sum[val] + 1 if sum[val] is defined.
How your code is executing:
When callback is called for the first time, sum is {} and val is 'y'. Since sum[val] or sum['y'] is undefined, 'y' is added as a key in sum and its value is 1. Same thing happens when callback function is called second time. After 2 calls, sum looks like { y: 1, n: 1 }.
In third call, since sum[val] is equal to 1, so previously added key y is overwritten with sum[val] + 1 which evaluates to 1 + 1. So after third call, sum looks like { y: 2, n: 1 }. Same thing happens in the subsequent calls to callback function.

Related

delete occurrences of an element if it occurs more than n times javascript

So I have this problem which I have been stuck on but have an answer but not sure exactly why it's working... Please can someone explain why this works?
function deleteNth(arr,n){
var cache = {};
return arr.filter(num => {
cache[num] = (cache[num]||0) + 1; // this is the line i am comfused about!!
return cache[num] <= n;
});
}
deleteNth([1,1,3,3,7,2,2,2,2], 3);
So through the filter function it'll run for each of the elements in the array.
The line you are confused about is setting the cache[num].
In the first iteration, num will be 1, and cache will be equal to {}, so cache[num] will be undefined.
It is setting it to (cache[num] || 0) which in real terms means if cache[num] OR 0. As cache[num] is undefined in the first instance, it'll be 0. It is then adding 1.
so each time the number is hit, it is adding one, and then it will return if the number of instances is below or equal the accepted number, in this case 3.
When it goes above that threshold, it'll be equal to false and now it won't be included as part of the filter.
cache[num]||0 means that if cache[num] doesn't have a key num then use the value 0.
This happens because the value cache[num] can be null in the first occurence
var cache = {}
console.log(cache[1]); // undefined
console.log(cache[1] || 0); // 0

Clarification on For/Over Loop with Conditionals

Reading through O'Reilly's JS Definitive Guide and came across this block of code:
let freq = {};
for (let item of "alabama") {
if (freq[item]) {
freq[item]++;
} else {
freq[item] = 1;
}
}
Just want to go over some of the the syntax and implications:
Assigning an empty object to "freq" variable
Running the for/of loop over the given string
If statement checks if freq[item] returns true .. I get that part but what will trigger that truthy value?
And thus what how would a falsy value be triggered to produce a value of 1?
Thank in advance!
First, keep in mind that when iterating over a string with for..of, the item declared for each loop (which you've named item) is each character of the string.
Since the object starts out empty, freq[item] will initially be undefined. For example, on the first iteration, {}['a'] is undefined, which is falsey, so the else is entered:
freq['a'] = 1;
On subsequent iterations, when the character a is found, the a property will exist on the object, so the if is entered, incrementing that property value:
freq['a']++;
The first time you find a letter not in the object it will return undefined
1) a
freq['a'] will be undefined
therefore the code will set a 1 to it
freq['a'] = 1
2) l will go through the same steps as #1
3) a
freq['a'] will be 1
so it's truthy therfore we add 1 to it
freg['a'] ++; which will make it 2
Then you can follow same pattern to figure out the rest
in javascript the following are false
"",false,0,undefined,null..
in you case freq is an empty object
freq ={}
in first iteration of loop
item = 'a'
freq[item] will be undefined
if freq[item] will be false
so in else freq[item] = 1 ie. freq={a:1}
same way for second iteration freq={a:1,l:1}
for third iteration
item = 'a'
freq[item] will be 1
if freq[item] will be true and increments freq={a:2,l:1}

value in array that occurs odd number of times- what is happening here?

I came across this code when I checked how to find the number that occurs odd number of times.
I tried to understand everything but I ca figure this out.
Please tell what is happening step by step and what each variable means.
Thank you!
function findOdd(A) {
let counts = A.reduce((p, n) => (p[n] = ++p[n] || 1, p), {});
return +Object.keys(counts).find(k => counts[k] % 2) || undefined;
reduce is an Array method which should reduce an array to a single value, which could be an array itself, an object or any flat variable type
reduce will take a function and an initial accumulating object as parameters
The function is called for each element in the array and be passed the accumulating object as first parameter (p) and the single array item as second parameter (n)
The function is in this case an arrow function expression
The function body consists of two expressions connected by the comma operator. The comma operator will return the rightmost expression as a result, in this case p.
The first expression of the comma operator (p[n] = ++p[n] || 1) will return 1 if p[n] is not set, otherwise will increment p[n] and return the result. Thanks to the short-circuit evaluation of the logical OR (||)
This could be written a little bit more detailed as
A.reduce(function (p, n) {
if (p[n]) {
p[n] = p[n] + 1
} else {
p[n] = 1
}
return p
}, {});
As a result you receive an object which counts the appearance of every value in the array
Then you have the return statement which will return the first key of counts which has an odd value
It does this by first creating an Array of the keys of counts with Object.keys.
It then iterates over those keys and checks, whether the modulo division by 2 (% 2) of the value corresponding to every key is a truthy value (in this case not zero) and then return that key.
It will always return the first key with that property
At the end this found value is converted to a number with the unary plus operator
If no value was found, undefined is returned
2 methods are used are used here that you need to understand.
reduce : read about it here https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/reduce
find read about it here: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/find
the below statement makes a map of a number vs its occurence
let counts = A.reduce((p, n) => (p[n] = ++p[n] || 1, p), {})
and then the second statement searches the map for an element which occurs odd number of times and if no such element it found it returns undefined
return +Object.keys(counts).find(k => counts[k] % 2) || undefined

Javascript reduce gotcha - skips first iteration?

Why does javascript's implementation of reduce skip execution for the first iteration?
[1,2,3].reduce((acc, val) => {
console.log('acc',acc);
console.log('val',val)
return acc + val;
});
// acc 1
// val 2
// acc 3
// val 3
// 6
I notice that the first statement execution never runs (in this case, I would have expected there to be 6 console logs, 2 for each element). This was very unexpected behavior when I was trying to execute a function with a side effect within each iteration with reduce.
In other languages that I've used, every iteration of the list passed executes. Are there examples otherwise?
Why does this happen and why is the implementation of javascript's native Array reduce like this?
========================= EDIT 1/Solution ========================
To make sure it goes through the first iteration, give it an initial value (the 2nd argument here/ 0 in this case)
[1,2,3].reduce((acc, val) => {
console.log('acc',acc);
console.log('val',val)
return acc + val;
}, 0);
That is because of the fact that on every iteration, the first value is treated as a return value (or the accumulator).
Straight from here, you can see
The accumulator accumulates the callback's return values; it is the
accumulated value previously returned in the last invocation of the
callback, or initialValue, if supplied (see below).
If we look at the source code here, we can see how it's implemented:
Array.prototype.myReduce = function(callback, initialVal) {
var accumulator = (initialVal === undefined) ? undefined : initialVal;
for (var i = 0; i < this.length; i++) {
if (accumulator !== undefined)
accumulator = callback.call(undefined, accumulator, this[i], i, this);
else
accumulator = this[i];
}
return accumulator;
};
In the else structure, we can see that if the value is undefined, we set it to the i-th subindex in the array; which, for the first iteration, is the first one. After that, it becomes the callback (return) value of the iterations which follow.
If you want, you can backtrack and check the output.

JavaScript: Writing a reduce function, trouble with callback function that subtracts values

I'm working to solve a code challenge in JavaScript where I am tasked with creating a function, called reduce, that will reduce a collection to a value which is the accumulated result of calling a function on each item over which I've iterated. The three parameters to include are array, callback, and start. Start is the index at which to begin, and if not provided as an argument defaults to the index zero.
Below is what I have currently:
function reduce(array, callback, start) {
if(typeof start === 'number'){
var initVal = start;
} else {
var initVal = 0;
}
return array.reduce(callback, initVal);
}
I have some tests against which I can test my solution, and my current work is failing only one test involving a callback function that subtracts the values. Here is the test I'm currently failing:
var difference = function(tally, item) {return tally - item; };
var total = reduce([1, 2, 3], difference);
expect(total).to.equal(-4);
Guidance is greatly appreciated.
Edited to add working solution:
function reduce(array, callback, start) {
if( typeof start === 'undefined' ){
return array.reduce(callback);
} else {
return array.reduce(callback, start);
}
}
Your code does not work since you're misusing the start which is intended to be an element index to start with with the initial value.
So for the [1, 2, 3] array as an input and the subtraction function as a callback what you are getting is:
The reducer accumulator is initialised with 0 (what you are supposed to not do actually)
0 - 1 -> -1
-1 - 2 -> -3
-3 - 3 -> -6
What you should have done instead:
There is no third parameter passed, so you're iterating from the beginning of the array.
Accumulator is not initialised explicitly, so the first element is passed to it, hence acc = 1
1 - 2 -> -1
-1 - 3 -> -4

Categories