If I have a function like _.transform.
Somewhere within the iteratee function I encounter an error; how do I exit from the _.transform function?
i.e.
{
try {
fs.readFileSync('dog_pics');
} catch(e) {
return;
}
}
What about _.map? Which expects return statements.
_.transform callback can return false in order to stop iterating.
From lodash examples:
_.transform([2, 3, 4], function(result, n) {
result.push(n *= n);
return n % 2 == 0;
});
// → [4, 9]
As you can see, iteration breaks on third step, when n === 3
_.map and _.reduce doesn't support iteration stopping
Since _.transform builds a new return object, returning without setting a pushing onto the result would allow you to "jump" out of that iteration.
(I haven't actually tested this code.)
Related
It is standard practice to continue inside a loop if a certain condition is met/unmet. In a Javascript forEach loop, this produces a syntax error:
const values = [1, 2, 3, 4, 5];
values.forEach((value) => {
if (value === 3) { continue; }
console.log(value);
})
SyntaxError[ ... ]: Illegal continue statement: no surrounding iteration statement
This happens whether I use function or an arrow function. How can you continue inside a forEach loop?
Obviously, you could do an inverse case (if (value !== 3) { ... }), but that is not what I'm looking for.
As #robertklep stated forEach() is not a loop, it is a function. You cannot use the continue keyword inside a forEach loop because its functionality is meant to loop each item in the array.
To achieve the similar behavior you can use,
for(let item of values){
if (item === 3) {
continue;
}
console.log(item);
}
For practical purposes, return in a forEach() callback is equivalent to continue in a conventional for loop but it isn't the most idiomatic use of functional programming patterns
To solve that, you can filter before you loop:
const values = [1, 2, 3, 4, 5];
values.filter(v => v !== 3).forEach((value) => {
console.log(value);
})
These are the full instructions for what I am trying to accomplish :
You will be provided with an initial array (the first argument in the destroyer function), followed by one or more arguments. Remove all elements from the initial array that are of the same value as these arguments.
This is the solution I have:
function destroyer(arr) {
var args = Array.prototype.slice.call(arguments);
args.slice(0,1);
return arr.filter(function(elements) {
return args.indexOf(element) === -1;
});
}
Keep in mind that there could be any number of arguments (not just 2 or 3).
The solution I have isn't working. What is wrong with my current solution and how can I fix it with an explanation?
Your solution is almost working.
The problems:
args.slice(0,1); does not modify the array (anyway this method just returns an array with the first element). Use args.shift() instead to remove the first element
function(elements) should be function(element) in the filter callback.
A working solution:
function destroyer(arr) {
var args = Array.prototype.slice.call(arguments);
args.shift();
return arr.filter(function(element) {
return args.indexOf(element) === -1;
});
}
console.log(destroyer([1, 2, 3, 5, 5], 1, 5)); // prints [2, 3]
Check the working demo.
I am practicing solving problems with recursion for a class.
I am solving the problems on this site : http://www.w3resource.com/javascript-exercises/javascript-recursion-functions-exercises.php
The question I am referring to is stated : Write a JavaScript program to get the integers in range (x, y).
Example : range(2, 9)
Expected Output : [3, 4, 5, 6, 7, 8]
Before looking at the solution I came up with this:
var range = function (start, end) {
var result = [];
var accumulator = start;
var accumulate = function () {
accumulator++;
if (accumulator === end) {
return;
} else {
result.push(accumulator);
}
accumulate();
};
accumulate();
return result;
};
The solution on the site is this:
var range = function(start_num, end_num)
{
if (end_num - start_num === 2)
{
return [start_num + 1];
}
else
{
var list = range(start_num, end_num - 1);
list.push(end_num - 1);
return list;
}
};
Is my solution technically still recursive? I had a similar answer on a quiz recently and I was told my solution is essentially iterative.
Though you use recursion, you have simply written a loop in the form of recursion.
I am going to answer this from the purely academical standpoint. If you want to avoid the intermediate state (result) and use purely functional constructs, I would write it like this
function range(start, end) {
function recRange(current, end) {
if (current > end)
return [];
return [current].concat(recRange(current + 1, end));
}
return recRange(start + 1, end - 1);
}
console.log(range(2, 9));
// [ 3, 4, 5, 6, 7, 8 ]
If you see here, we create a new function within the range function, which recursively creates a new array on every iteration (remember: this is not highly performant code, you can simply use loops and be done with this problem efficiently).
The base condition of the recursion is current < end. Once that is met, the recursion stops and an empty array is returned. In all the levels, a new array with the current value is concatenated with the result of the recursive call. So, the evaluation of the calls are roughly understood like this
[3].concat(recRange(3 + 1, end));
[3].concat([4].concat(recRange(4 + 1, end)));
...
at the end, when the recursion unwinds, the values will be like this
[3].concat([4].concat([5].concat([6].concat([7].concat([8].concat([]))))))
[3].concat([4].concat([5].concat([6].concat([7].concat([8])))))
[3].concat([4].concat([5].concat([6].concat([7, 8]))))
[3].concat([4].concat([5].concat([6, 7, 8])))
[3].concat([4].concat([5, 6, 7, 8]))
[3].concat([4, 5, 6, 7, 8])
[3, 4, 5, 6, 7, 8]
and that will be returned as the result.
To make your solution recursive, it should return some value and somehow combine the result of the recursive call to form the return value of the original call.
Let me illustrate that with an example, by modifying your solution:
var range = function (start, end) {
var accumulate = function (accumulator) {
if (accumulator === end - 1) {
return [accumulator]; // Stop condition
} else {
// Recursive block
var result = accumulate(accumulator+1); // recursive call
result.unshift(accumulator); // combine result
return result
}
};
return accumulate(start);
};
The modified accumulate function will return a one-element list for the stop condition, the simplest case it handles, where accumulator reaches the last value to return.
In the example range(2,9), the stop condition will return [8].
Then in the caller, the recursive block
var result = accumulate(accumulator+1);
result.unshift(accumulator);
return result
will take the list [8], and preprend the current value of accumulator (7), so it'll return [7,8].
...and the caller of accumulator(7), will receive [7,8] and preprend the value 6 to the list, to return [6,7,8].
At the end, the original call to accumulator(2) will generate the expected result [2,3,4,5,6,7,8].
Is my solution technically still recursive?
Yes. You're using tail recursion; however, since no arguments are being passed to accumulate() I can see why someone may say it's essentially iterative. You could easily replace your recursive call with a loop. Recursive algorithms typically leverage the stack.
Because of Javascript's closures, it is harder to understand the concept of recursion in Javascript compared to other languages like C++ or Java or C#.
To understand recursion, you must first understand recursion. :)
While going through Eloquent Javascript (Chapter 6) there is a reference to higher-order functions in Javascript. While there is an example provided in Chapter 3, I believe it could be a bit simpler since I still don't fully understand the concept. After searching the web I can't seem to find any succinct examples of a higher-order function.
I'd like to see a basic/simple higher-order function in Javascript that will explain the concept.
Higher functions are concepts from functional programming. In briefly, a higher function is a function which takes another function as parameter. In javascript, some higher functions are added recently.
Array.prototype.reduce
//With this function, we can do some funny things.
function sum(array){
return array.reduce(function(a, b){ return a + b; }, 0);
}
So, in the above sample, reduce is a higher order function, it takes another function, the anonymous function in the sample, as a parameter. The signature of reduce looks like this
reduce(func, init);
//func is a function takes two parameter and returns some value.
// init is the initial value which would be passed to func
//when calling reduce, some thing happen
//step 1.
[1, 2, 3, 4, 5].reduce(function(a, b){ return a + b }, 0);
//step 2.
[2, 3, 4, 5].reduce(function(a, b){ return a + b}, 0 + 1);
//step 3.
[3, 4, 5].reduce(function(a, b){ return a + b}, 0 + 1 + 2);
//...
As you can see, reduce iterate an array, and apply the func with init and first element of that array, then bind the result to init.
Another higher order funciton is filter.
Array.prototype.filter
//As the name indicates, it filter out some unwanted values from an Aarry. It also takes a function, which returns a boolean value, true for keeping this element.
[1, 2, 3, 4, 5].filter(function(ele){ return ele % 2 == 0; });
With the above two examples, I have to say higher order function is not that much easy to understand, especially reduce. But that's not complex, with higher order function, actually your code would be more clean and readable. Take the filter as example, it tells people that it throws all odd numbers away.
Here I'd like to implement a simple filter function to show you how.
function filter(array, func){
var output = [];
for(var i = 0; i < array.length; i++){
if(func(array[i])) output.push(array[i]);
}
return output;
}
All you know that arguments is a special object that holds all the arguments passed to the function.
And as long as it is not an array - you cannot use something like arguments.slice(1).
So the question - how to slice everything but first element from arguments?
UPD:
seems like there is no way without converting it to an array with
var args = Array.prototype.slice.call(arguments);
If someone posts another solution it would be great, if not - I'll check the first one with the line above as an answer.
Q. How to slice everything but first element from arguments?
The following will return an array containing all arguments except the first:
var slicedArgs = Array.prototype.slice.call(arguments, 1);
You don't have to convert arguments to an array first, do it all in one step.
Meddling with array functions is not actually necessary.
Using rest parameter syntax ...rest is cleaner and more convenient.
Example
function argumentTest(first, ...rest) {
console.log("First arg:" + first);
// loop through the rest of the parameters
for (let arg of rest) {
console.log("- " + arg);
}
}
// call your function with any number of arguments
argumentTest("first arg", "#2", "more arguments", "this is not an argument but a contradiction");
...Rest
See the example Fiddle
See MDN Documentation page
From https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/arguments:
You should not slice on arguments because it prevents optimizations in
JavaScript engines (V8 for example). Instead, try constructing a new
array by iterating through the arguments object.
So Paul Rosiana's answer above is correct
This can be a way:
var args = Array.from(arguments).slice(1);
You can "slice without slicing" by procedurally walking the arguments object:
function fun() {
var args = [];
for (var i = 1; i < arguments.length; i++) {
args.push(arguments[i]);
}
return args;
}
fun(1, 2, 3, 4, 5); //=> [2, 3, 4, 5]
You can use the method [].slice.call(arguments, 1)
[].slice will return you the slice function object and you can call it as the arguments and 1 are the parameters
You can use ...rest within the function to separate the first and the rest of the arguments:
function foo(arr) {
const [first, ...rest] = arguments;
console.log(`first = ${first}`);
console.log(`rest = ${rest}`);
}
//Then calling the function with 3 arguments:
foo(1,2,3)
you can use this too
function arg(myArr) {
let arg = Object.values(arguments).slice(2, 4);
console.log(arg);
return arg;
};
arg([1, 2, 3], 4, [5,6], 7)
see here for reference: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/values
...
Arguments type is iterable, so using the ES6 (ES2015) spread ... operator, then use Array.slice([start], [end]) method, such as
function omitFirstAndLastArgument(value) {
const args = arguments.length > 2 ? [...arguments].slice(1, -1) : [];
return args;
}
omitFirstAndLastArgument(1, 2, 3, 4, 5, 6); // [2, 3, 4, 5]