I'm constructing a loop for with a function.
The function loop takes a value, a test function, an update function, and a body function. Each iteration, it first runs the test function on the current loop value and stops if that returns false. Then it calls the body function, giving it the current value. Eventually, it calls the update function to create a new value and starts from the beginning.
loop(10, n => n > 0, n => n - 1, console.log);
function loop(a, b, c, d) {
let currentValue = a;
let i;
for (i = 0; i < currentValue; i++) {
if (b(currentValue)) {
d(currentValue);
update(c);
function update(c) {
var executeUpdate = c(currentValue);
currentValue = executeUpdate;
};
} else {
return;
}
};
}
// OUTPUT: 10, 9, 8, 7, 6
Why does this function stop at 6 instead of 1?
function update(c) {
var executeUpdate = c(currentValue);
console.log('value of exeucteUpdate: ',executeUpdate, 'when i:', i)
currentValue = executeUpdate;
};
Do a console.log at your update function, you will notice when i == 4, executeUpdate is 5 and you updated the value of forloop and hence the loop terminates at this particular loop
You can use few console.logs to see it.
Actually the for-cycle ends when currentValue and i equals 5, therefore the condition is not met and cycle terminates.
However your condition does not make any sense, you are comparing true to some number (as you can see in the logs)
loop(10, n => n > 0, n => n - 1, console.log);
function loop(a, b, c, d) {
let currentValue = a;
let i;
for (i = 0; i < currentValue; i++) {
console.log(i, currentValue);
console.log(b(currentValue), currentValue)
if (b(currentValue) < currentValue) {
d(currentValue);
update(c);
function update(c) {
var executeUpdate = c(currentValue);
currentValue = executeUpdate;
};
} else {
console.log('I am not here');
return;
}
}
console.log('finished', i, currentValue);
}
Related
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!
I have a function 'sometimes' and want to return a function object from it.
Below is my code:
let add = (a, b) => {
return a + b;
};
myFunc = sometimes(add);
const outputArr = [];
for (let i = 0; i < 3; i++) {
outputArr.push(myFunc(2 + i, 3 + i));
}
function sometimes (inputFunc){
return function (a, b){
return inputFunc()
}
}
outputArr
I expect my outputArr variable to equal:
[5, 7, 9]
Instead mine equals:
[ NaN, NaN, NaN ]
What am I doing wrong?
You are not passing the parameters to the wrapped function. The add function tries to sum two undefined values and the result is NaN (not a number).
You have to pass the parameters to the wrapped function:
return function(a, b) {
return inputFunc(a, b); // <<<
}
Since sometimes is a higher order function, that needs to wrap different functions, with a changing number of parameters, it can't know the implementation of the wrapped function. To ensure that, you should use rest parameters (to collect the parameters to an array) and spread (to convert the array back to parameters) to pass the arguments to the wrapped function.
let add = (a, b) => {
return a + b;
};
myFunc = sometimes(add);
const outputArr = [];
for (let i = 0; i < 3; i++) {
outputArr.push(myFunc(2 + i, 3 + i));
}
function sometimes(inputFunc) {
return function(...args) {
return inputFunc(...args)
}
}
console.log(outputArr);
you can use your code as
function sometimes(a,b){
return a + b;
}
const outputArr = [];
for (let i = 0; i < 3; i++) {
outputArr.push(sometimes(2 + i, 3 + i));
}
console.log(outputArr);
now the output is
[ 5, 7, 9 ]
Here is what I have to do:
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.
My code:
function destroyer(arr) {
for(i=1; i < arguments.length; i++) {
x = arr.filter(filterer);
}
function filterer(val) {
return val !== arguments[i];
}
return x;
}
destroyer([1, 2, 3, 1, 2, 3], 2, 3);
But it doesn't work properly and returns the initial array not the filtered one. Where is my mistake?
Basically, you have two issues,
arguments[i] in wrong content, in a callback of the filter function,
function destroyer(arr) {
function filterer(val) { // <--------------------+
return val !== arguments[i]; // |
// ^^^^^^^^^^^^ this points to --+
}
for(i=1; i < arguments.length; i++) {
x = arr.filter(filterer);
}
return x;
}
no assignment of the result for further filtering.
Solution
take a function with a closure over the test value and return a function for further testing in the filter method.
use a variable with arr as start value and assign the filter result. Then return this value at the end.
function destroyer(arr) {
function filterer(testValue) { // take arguments[i] value
return function (val) { // return function as callback
return val !== testValue; // use testValue instead of arguments[i]
}
}
var x = arr // assign arr as start value for filtering
for (var i = 1; i < arguments.length; i++) {
x = x.filter(filterer(arguments[i])); // use filterer with a parameter
}
return x; // return result
}
console.log(destroyer([1, 2, 3, 1, 2, 3], 2, 3));
arguments scope is changed .
You want to use arguments[i] inside function filterer(val) {return val !== arguments[i];} as it is the arguments of the parent function which is destroyer.
If so , use filterer as arrow function to keep the scope of arguments.
function destroyer(arr) {
const filterer = (val) => { // 👈🏼 ⚠️ This is an arrow function
return val !== arguments[i]; // ⬅️ "arguments" refers now to "destroyer()" args
}
for(i=1; i < arguments.length; i++) {
x = arr.filter(filterer);
}
return x;
}
destroyer([1, 2, 3, 1, 2, 3], 2, 3);
make a copy of arguments object. As Abdennour said, scope of arguments object changes for filterer.
Also, make copy of input array and keep on filtering from that array only.. otherwise your result will just be filtered for last argument.
function destroyer(arr) {
var copy = arguments;
var x = arr;
for(i=1; i < copy.length; i++) {
x = x.filter(filterer);
}
function filterer(val) {
return val !== copy[i];
}
return x;
}
destroyer([1, 2, 3, 1, 2, 3], 2, 3);
I'm trying to use the reduce() method to find one skipped (missing) number in an array of (sometimes almost) consecutive numbers. Only one number will be missing at most.
This is my codepen: http://codepen.io/PiotrBerebecki/pen/zBrRVd
For example,
findMissing([1,2,3,5]) should return 4
findMissing([1,2,3,4]) should return undefined
findMissing([2,3,4,6]) should return 5
findMissing([2,4,5,6]) should return 3
The code that I developed seems to work fine if there is indeed a number that was skipped. But it returns an undesired value if all numbers are present. Would you know how to fix it?
My JS code:
function findMissing(arr) {
return arr.reduce(function(prev, curr) {
if (curr - prev !== 1) {
return curr - 1;
}
});
}
// This should return 4, and it indeed returns 4
console.log( findMissing([1,2,3,5]) );
// This should return 'undefined', but it returns 3
console.log( findMissing([1,2,3,4]) );
// This should return 5, and it indeed returns 5
console.log( findMissing([2,3,4,6]) );
UPDATE 1:
Based on the answers below, the following code delivers the desired outcome using the reduce() method:
// ****SOLUTION:****
function findMissing2(arr) {
return arr.reduce(function(prev, curr, index, array) {
if (curr === index + array[0]) {
return prev;
} else {
return index + array[0]++;
}
}, void 0);
}
console.log( findMissing2([1,2,3,4]) ); // Undefined
console.log( findMissing2([1,2,3,5]) ); // 4
console.log( findMissing3([2,3,4,6]) ); // 5
console.log( findMissing2([2,3,4,5]) ); // Undefined
console.log( findMissing2([2,4,5,6]) ); // 3
I would do this job as follows;
var a1 = [1,2,3,5],
a2 = [2,3,4,5],
a3 = [2,4,5,6],
res1 = a1.reduce((p,c,i,a) => c == i+a[0] ? p : i + a[0]++, void 0),
res2 = a2.reduce((p,c,i,a) => c == i+a[0] ? p : i + a[0]++, void 0),
res3 = a3.reduce((p,c,i,a) => c == i+a[0] ? p : i + a[0]++, void 0);
console.log(res1);
console.log(res2);
console.log(res3);
Note: void 0 is a very safe undefined value in JS. The above code will mutate the tested array. You might prefer to call like a1.slice().reduce... if you want to keep the tested array as it is.
Instead of reduce you should use for loop here
function findMissing(arr) {
var r = [];
for (var i = arr[0]; i <= arr[arr.length - 1]; i++) {
if (arr.indexOf(i) == -1) r.push(i);
}
return r;
}
console.log(findMissing([1, 2, 3, 5]));
console.log(findMissing([1, 3, 6]));
console.log(findMissing([10, 13, 16]));
Your reduce closure/callback function needs to return the value to be used as the next prev in the next iteration.
Because of this, in the second example, the first iteration returns undefined, as it does not enter the if block. The second iteration is passed the parameters of undefined, 3, where undefined - 3 !== 1 so it returns 2.
This propagates the way up your iterations, until it returns 3.
As such, I'm struggling to think of a way your reduce function could be adapted to correct this.
Perhaps using a simple for loop might be a bit more robust?
function findMissing(arr) {
for(var i = 1; i < arr.length; i++) {
if(arr[i] - arr[i-1] !== 1) {
return arr[i]-1;
}
}
}
As I said in comments, if you are looking for efficiency you could do it with recursion:
function findMissing(arr) {
if (arr.length === 1) return;
if(arr[1] - arr[0] !== 1){
return arr[0];
}
else{
return findMissing(arr.slice(1,arr.length));
}
}
Or even with a while loop:
function findMissing(arr) {
var i = 0;
while (arr[i+1] - arr[i] === 1) {
i++;
}
if (i < arr.length-1) return arr[i];
}
var findMissing = function (list) {
var expected_sum = (list[0] + list[list.length - 1]) * (list.length + 1) / 2;
var sum = list.reduce((a,b)=>a+b);
return expected_sum - sum;
}
console.log(findMissing([-5,-1,1,3,5,7,9,11]))
The function ev call the reduce function insight it and is suppose to return true if an even number is in the array(which I pass to the ev function) and false if the array has an odd number. My code works for even numbers, but fails for odd numbers (shows true still) and I don't know why! Someone knows why?
var even = function(num) {
return num % 2 === 0;
};
function reduce(array, init, func) {
var curr = init;
for (var i = 0; i < array.length; i++) {
curr = func(curr, array[i]);
}
return curr;
}
function ev(arr, func) {
if (arr.length > 0) {
if (reduce(arr, 0, func)) {
return true;
} else {
return false;
}
}
return true; //thats i the array is empty
}
ev([0, 11, 28], even);
Perhaps you are supposed to use the built-in map/reduce functions in Javascript?
function isEven(val) {return !(val % 2)}
function or(a, b) {return a || b}
function containsEven(arr)
{
return arr.map(isEven).reduce(or)
}
Edit 1:
Or, even better, you can use the properties of even/odd multiplication to just check to make sure the product of the elements of the array is even:
function mult(a, b) { return a * b }
function containsEven(arr)
{
return !(arr.reduce(mult) % 2)
}
Edit 2:
Now that it is clear that we want to check if all elements in the array are even, we would have the following code:
function isEven(val)
{
// Equivalent to val % 2 === 0
return !(val % 2)
}
function and(a, b) {return a && b}
// Checks to see if all elements in arr pass the checkFn
function ev(array, checkFn)
{
return array.map(checkFn).reduce(and)
}
//can now call ev([0, 11, 28], isEven)