Trying to understand how to use _.reduce - javascript

I'm trying to solve this question:
Use _.reduce to multiply all the values in an array.
Here's what I came up with:
var product = _.reduce([1, 2, 3], function(x, y){ return x * y; }, 0);
= 9
Is this close? I don't feel like I'm fulling grasping reduce(). Please help.

You should either omit the final 0 parameter from your call to _.reduce, or replace it with 1, depending on the semantics you want to achieve if you were to supply an empty array.
Rather than think of variables x and y in the callback, consider them as accumulator and current. In the first pass the "initial value" parameter is passed as accumulator, and in each subsequent pass the result of the previous pass is supplied as accumulator.
The 0 you erroneously supplied is passed as the first value of accumulator, and therefore every subsequent multiplication also results in 0.
Fortunately, the specification for reduce says that if you omit that initial value parameter then it will take the first element of the supplied array to be in the initial value for accumulator and then only iterate from the second element onwards.
If you don't supply an initial value then the array must have at least one element in it.

Related

splice(0) vs splice(0,undefined)

Splice with no second argument behaves as expected:
['a','b','c'].splice(0) // Returns ['a','b','c']
But Splice with a undefined second argument behaves differently:
['a','b','c'].splice(0, undefined) // Returns []
Can someone explain to me the difference? I would expect the same (first) result.
It suggests that internally, splice is using "arguments.length" or similar, to change its behaviour, rather than checking the arguments.
It suggests that internally, splice is using "arguments.length" or similar
Yes, that's exactly what happens internally.
If there is exactly one argument passed, it removes all elements until the end.
If there are more arguments passed, it takes the second one, casts it to an integer and uses it for the count of elements to be deleted. When you are passing undefined, it is cast to the number value NaN, which leads to the integer 0 - no elements are removed.
According to docs, Array.prototype.splice returns deleted elements.
It also says that when second parameter deleteCount equals 0 then nothing is deleted.
So, in the first case you are deleting everything after index 0 inclusive and the result is whole array.
In the second case you are deleting 0 elements and the result is empty array.
The reason the second result is empty is because, if the second parameter is 0 or negative, no elements are removed.
This is of course according to mozzila.
Syntax is:
splice(index, delete, insert)
There is condition actually "if delete part assigning "false" values which are (undefined, 0, false) it will return empty array".
That is why in second syntax returning blank array"
['a','b','c'].splice(0) //returns complete array
['a','b','c'].splice(0, undefined) // Returns []

How the order of arguments works in a reduce helper method?

// this is the array
var numbers = [10,20,30];
// Now I want to get the sum of all the elements of numbers array
// this will give 60
numbers.reduce(function(sum,number){
return sum + number;
},0);
// this also gives 60
numbers.reduce(function(number,sum){
return sum + number;
},0);
I am just learning ES6, I tried looking at MDN but couldn't find the explanation. I just want to know how javascript detects the argument with initial value to be zero and which it detects to be the array elements.
Or does it arbitrarily chooses the argument values.
According to MDN, the first argument will always be the sum/accumulator, and the second will be the value.
Both parameters have no inherit binding to a name, so you can name both the sum and the value whatever you wish.
In your example, the first one works probably as you expected, with the sum as the first parameter and the value as the second parameter. In your second example, it works the exact same way, the only difference being that you named the 'sum' as 'number' and the 'value' as 'sum'.
JS may be weird but it's not messing with your arguments in this case. You're just naming the arguments differently.
From MDN:
The first time the callback is called, accumulator and currentValue
can be one of two values. If initialValue is provided in the call to
reduce, then accumulator will be equal to initialValue, and
currentValue will be equal to the first value in the array. If no
initialValue is provided, then accumulator will be equal to the first
value in the array, and currentValue will be equal to the second.
Note: If initialValue isn't provided, reduce will execute the callback
function starting at index 1, skipping the first index. If
initialValue is provided, it will start at index 0.
The first param, "sum", is the accumulator. The second param, currentValue, is "number".
Here's the syntax of the reduce method.
array.reduce(function(total, currentValue, currentIndex, arr), initialValue)
where, function is used to reduce the array and will be invoked for each array element.
This function uses first argument passed to it as an accumulator to store the result.
Each element of the array will be passed as the second argument to the function.
Just like other functions in JavaScript, the order of the parameters matter(not their name).
While these two parameters are required to be present in your function, it can have two more optional parameters, viz currentIndex and the array itself.
And finally, the optional initValue passes to reduce function will be used to initialize the accumulator.
You can read more about it here.

What exactly `Function.prototype.length` means?

There was a Function.prototype.arity property purposed for getting number of arguments function expects. Now it is obsolete (since JS 1.4), and the same goal has Function.prototype.length.
But recently I've found an article in the documentation about Array.prototype.reduce method. And it clearly says that the method has property length equal to 1:
The length property of the reduce method is 1.
This exact article has a header with number of arguments, and there are two of them:
Array.prototype.reduce ( callbackfn [ , initialValue ] )
callbackfn and initialValue (optional).
So it is not clear to me, what exactly the purpose of length property.
If it is used to give useful information to developer, then it actually does not.
If it is just a technical automatically-generated property that just indicates number of arguments in function definition, then why don't maintain its consistency?
Array.prototype.reduce's length is 1 because the second parameter is optional.*
So it is not clear to me, what exactly the purpose of length property.
To tell the developer how many declared parameters it has prior to the first parameter with a default value (if any) or the rest parameter (if any), whichever is earliest in the parameter list. Or as the spec puts it:
The value of the length property is an integer that indicates the typical number of arguments expected by the function.
The exact algorithm is in the spec's Static Semantics: ExpectedArgumentCount section.
If it is used to give useful information to developer, then it actually does not.
Well, that's a matter of opinion. :-)
When you have a language like JavaScript where functions can only express an expectation but may be called with fewer or more arguments, and particularly when you add the concepts of default parameter values and rest parameters, it's not surprising that the arity of function is a bit of a soft concept.
Some fun examples:
function ex1(a) { } // length is 1, of course
function ex2(a, b = 42) { } // length is 1, `b` has a default
function ex3(a, b = 42, c) { } // length is 1, `b` has a default and
// `c` is after `b`
function ex4(a, ...rest) { } // length is 1 yet again, rest parameter doesn't count
* In ES5, its declaration in JavaScript would be:
function reduce(callback) {
// ...
}
...and then it would use arguments.length to determine whether you'd supposed an initialValue.
In ES2015+ (aka "ES6"+), it would either still be like that, or be like this:
function reduce(callback, ...args) {
// ...
}
...and use args.length to see if there was an initial value.
Or possibly like this:
const omitted = {};
function reduce(callback, initialValue = omitted) {
// ...
}
...and then use initialValue === omitted to know whether you'd supplied an initial value. (The default value of initialValue can't be undefined or null or similar because the function has to branch based on whether the argument was provided [not what its value is]. But we can do that with object identity.)

d3 bisector not working with array of objects

I have an array of objects
var s = [{"4":0},{"5":0},{"8":0},{"14":0}];
and a d3.bisector():
var bd = d3.bisector(function(d,y){ return y;}).left;
When calling it like this
bd(s,5)
it outputs 0. The bisector fails if I use "key" of the object instead of a value in the accessor function. Can someone shed some light as to why is this happening?
You need to make two adjustments to make it work:
To use the keys for comparision, you have to explicitly access them. Given your array of objects this could be done by d3.keys(d)[0], thereby comparing the first and only key. In case you want to numerically compare the keys, this will be +d3.keys(d)[0].
Because you specified your callback as function(d,y) {}, i.e. taking two arguments, the function is expected to be a comparator returning boolean values. The easiest way in your case would probalby be to provide a one-argument callback being an accessor to the objects keys.
The following code should work as expected
s = [{"4":0},{"5":0},{"8":0},{"14":0}];
var bd = d3.bisector(function(d) {
return +d3.keys(d)[0];
}).left;
console.log(bd(s, 5)); // 1
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>

get element from arbitrary list in javascript

i have a function in javascript where i need to retrieve the last element of the list. the list can be an array, string, list in numbers (not array). I tried converting the list into a String and then an array and retrieving it by index, but that's not working.
Here is the code I tried:
function last(list){
var array = new String(list);
array = array.split("");
return array[array.length-1];
}
I don't understand what the problem is because test suite says Expected: 5 instead got: 5
I am using code wars and did not write the tests. Is it expecting a Number and getting a String '5' ? I don't understand types in loosely typed languages very well yet.
from the comments, I think you mean you want to either return the last element in an array, the last character in a string, or the last argument passed if multiple arguments were passed. This would do it:
function last() {
if (arguments.length > 1) { // first we handle the case of multiple arguments
return Array.prototype.pop.call(arguments);
}
value = arguments[0]
if (typeof value === 'string') { // next, let's handle strings
return value.split('').pop();
}
if (Object.prototype.toString.call( [] ) === '[object Array]') {// Arrays are of type object in js, so we need to do a weird check
return value.pop();
}
}
arguments is a pseudo-array that contains all arguments passed into the function, so for last(1,2,3,4,5), arguments would be roughly [1,2,3,4,5]. It's not exactly that though, because arguments has all args in order and a length property, but it's prototype isn't Array, so it isn't truly [1,2,3,4,5] and lacks all of array's functions. This is why we need to call pop in the context of arguments (in javascript, Function.prototype.call calls the function passing the first arguments as the value of this, and all the rest of the arguments into the arguments pseudo-array, so for example last.call([], 1, 2, 3) would call last in the context of a new array and with arguments roughly equal to [1,2,3]).
the rest of the code is pretty straightforward, except for the check to see if value is an array, which is further explained here.
Finally, pop is an array method that removes the last element from an array and returns it.

Categories

Resources