High-order function "every" method PROBLEM - javascript

I have a problem to solve in ELOQUENTJS book, can somebody help and tell me what's wrong in this code.
This is my code so far.
function every(array, test) {
for (let i of array) {
let curArr = array[i];
if (test(curArr)) {
return true;
} else {
return false;
}
}
}
console.log(every([1, 3, 4, 12], n => n < 10));
// returns true
I'm expecting to see false as a return, but somehow it returns true.

Your first issue is with your return true. This line will make your function "exit", thus stopping any of the remaining code from executing. As 1 < 10, you are immediately returning true from your function. Instead, you can return true only once you have checked every element.
Your other issue is that a for..of loop will get every element in your array, not every index like you think you're doing so i infact actually is equal to your curArr variable:
function every(array, test) {
for(let curArr of array){
if(!test(curArr)){
return false;
}
}
return true;
}
console.log(every([1, 3, 4, 12], n => n < 10));

Related

Check if an element is an array using recursion

I would like to check if an element inside an array is another array. I'm solving a code challenge where the problem is iterating through an array and checking for a 7 but if an
element is an array I would like to continuously check each nested array for a 7.
I have console.log() in my first 'if' statement and I've seen that sevenBoom() is being called more than once. But for some reason it's not returning 'Boom!'
SevenBoom should return 'Boom!' if there's a seven.
function sevenBoom(arr) {
if (arr.includes(7)) {
return "Boom!";
}
arr.forEach((val) => {
if (Array.isArray(val)) sevenBoom(val);
});
}
sevenBoom([1, 3, 4, 6, [7]) // Returns undefined
sevenBoom([3, 7, 8, 9]) // Returns 'Boom!'
You could take a boolean value as result and use Array#some for checking arrays.
function hasSeven(array) {
function seven(a) {
return a.includes(7) || a.some(v => Array.isArray(v) && seven(v));
}
return seven(array)
? 'Boom!'
: 'There is no 7';
}
console.log(hasSeven([7]));
console.log(hasSeven([[7]]));
console.log(hasSeven([[[7]]]));
console.log(hasSeven([]));
console.log(hasSeven([[]]));
console.log(hasSeven([[[]]]));
const sevenBoom = (arr) => {
const recurse = (arr) => arr.some(n => Array.isArray(n) ? recurse(n) : n === 7);
if (recurse(arr)) {
return 'Boom';
}
}
This is assuming what should be returned other than 'Boom' is void. It's a bit of an awkward place for recursion since you want to return a string if you meet some criteria and nothing otherwise.
Firstly you need to return the value from your second if condition too.
But forEach() cannot be interrupted (for ex: with a return statement) and will run for all items. So you can keep track using a flag variable outside the forEach() and return your result on that basis.
function sevenBoom(arr) {
if (arr.includes(7)) {
return "Boom!";
}
let found = false;
arr.forEach((val) => {
if (Array.isArray(val)) if(sevenBoom(val)) found="Boom!";
})
return found;
}
console.log(sevenBoom([1,2,3]));
console.log(sevenBoom([1,2,7]));
console.log(sevenBoom([1,2,[2,7]]));
console.log(sevenBoom([1,2,[2,3,[4,5]]]));
console.log(sevenBoom([1,2,[2,3,[4,7]]]));
Note: How sevenBoom() can be directly used inside an if statement. This is because of the concept of truthy and falsy values.
PS: As mentioned above, forEach() will run for all items, no matter what. You can use any other looping mechanism like a simple for loop, some() etc. I just copied your code and hence used forEach()
I would check if an element is seven in the same loop that you are checking if an element is an array that way you can avoid going through the array unnecessarily.
const sevenBoom = arr => {
for (const ele of arr) {
if (ele === 7) return 'Boom';
if (Array.isArray(ele)) {
//this prevents you from halting your function early
//you only want to return in the loop if a 7 is found
if (boom(ele) === 'Boom') return 'boom'
}
}
}
You can use the .flat(depth) method to flatten each array before using the .includes() method. Choose a depth that would cover all possible arrays for your project.
function sevenBoom(arr) {
return arr.flat(10).includes(7) ? 'Boom!' : '-'
}
DEMO
let a = [1, 3, 4, 6, [7]],
b = [3, 7, 8, 9],
c = [1,2,[5,6,[3,5,[7,6]]]],
d = [0],
e = [1, [5, 4], 3, 5, [7]];
function sevenBoom(arr) {
return arr.flat(10).includes(7) ? 'Boom!' : '-'
}
for(let arr of [a,b,c,d,e]) {
console.log( sevenBoom( arr ) );
}
console.log( e ); //Original array remains unchanged
If 7 is not present in the root array, then your function isn't returning anything.
Try this, just a minor refactoring:
function sevenBoom(arr) {
if (arr.includes(7)) return 'Boom!';
for (let val of arr) {
if (Array.isArray(val)) {
if (sevenBoom(val)) return sevenBoom(val);
}
}
return false;
}

Js if multiple values check if ==

I can create like that code in js? if example == 0, 2, 4, 6, 8 { code here } else if { code here } I mean check example have one of this value
I dont wanna create many lines code example if == 0 , if == 2 ets
Thanks for help
I think what you want to do is compare your 'example' with each of the values.
let's assume your array is 2,4,6,8,0
then what you can do is
let example = 3;
let array = [2, 4, 6, 8, 10];
if (array.includes(example)) {
// true statement
} else {
// false statement
}
Just make a function and check the values via a loop and based on that return either false or true, look at the snippet below. The values should be in an array!
function checkValue(value){
for (let i of [0,2,4,6,8]){
if (i === value) {
return false;
}
}
return true;
}
console.log('3: ', checkValue(3));
console.log('8: ', checkValue(8));
Alternatively if you want to see if the value is an odd number or not, you can use the remainder operator:
let i = 3;
console.log(i%2 === 1)

Return Command for Callback Functions

function twoSum(numbers, target) {
var result = [];
numbers.forEach(function(value, index) {
return numbers.forEach(function(value2, index2) {
if (value + value2 === target) {
result.push(index, index2);
return result;
}
})
})
return result;
}
twoSum([1, 2, 3], 4);
//Output - [ 0, 2, 1, 1, 2, 0 ]
Hi - I'm working on a particular codewars problem and I seem to be misunderstanding the usage of return for callback functions. In this particular problem I just want to find the first two sums of numbers that equal the target and push those index values into result. I don't want to keep iterating through my function after that - meaning I only want the first pair that's found. My current output gives me all the index values for the target sum. Not just the first 2. It seems I am not using my return commands correctly. My current line of thought is that return result returns a value to my nested callback of parameters (value2, index2). That result is then returned to my outside function of (value,index). Why does my loop not cease after that return?
It doesn't end because .forEach cannot be terminated early. forEach is not paying any attention to the values you return. If you want to terminate early you'll need to use a different approach.
If you want to stick with array methods, there are .some and .every. The former continues until a run of your function returns true, and the latter continues until a run of your function returns false. These are meant for doing compound OR's and compound AND's with every element of the array, but they can kinda be used for your case too.
numbers.some(function(value, index) {
return numbers.some(function(value2, index2) {
if (value + value2 === target) {
result.push(index, index2);
return true;
}
return false;
})
})
Or you could use a standard for loop, with the break keyword when you want to stop the loop.
Beside the not working return statement for a outer function, you need to take a different approach which uses only a single loop and an object for storing the index of the found value.
function twoSum(numbers, target) {
var indices = {};
for (let i = 0; i < numbers.length; i++) {
const number = numbers[i];
if (number in indices) return [indices[number], i];
indices[target - number] = i;
}
}
console.log(twoSum([1, 2, 3], 4));

Clarification on reduce to create filter in javascript

My main goal for academic purposes is to solve this problem and for the most part I did. Also I wanted to make sure that I was not missing a fundamental part of reduce by not understanding what is wrong with my code.
This is how I would solve it, I've attached my reduce function as well as filter function. I believe my reduce function works however, my filter function isn't quite working so well as I can't pass my test cases.
1) Why am i not hitting the last element of the array?
I've noticed that prev and curr actually never return 5 at any point of the reduce function. Am I missing something in my reduce function?
myArray = [1,2,3,4,5];
function each(collection, action){
if(Array.isArray(collection)){
for(var i = 0; i < collection.length; i ++){
action(collection[i]);
}
}
else if(typeof(collection) === "object"){
for (var property in collection){
action(collection[property]);
}
}
}
function reduce(collection, combine, start){
each(collection, function(element){
if(start === undefined){
return start = element;
}
else {
return start = combine(start, element);
}
});
return start;
}
function filterR(collection, predicate){
var aR = [];
reduce(collection, function(prev, curr){
if(predicate(prev)){
aR.push(prev);
}
if(predicate(curr)){
aR.push(curr);
}
});
return aR;
}
console.log(filter(myArray, function(val){return val % 5 === 0;})); //expected [5]
console.log(filter(myArray, function(val){return val <= 5;})); //expected [1,2,3,4,5]
I can't diagnose your problem because I don't know what your each procedure is.
Anyway, it doesn't matter; you're overthinking it.
reduce is very simple to implement by hand.
function reduce(f, start, arr) {
if (arr.length === 0)
return start;
else
return reduce(f, f(start, arr[0]), arr.slice(1));
}
// example
function add(x,y) { return x+y; }
reduce(add, 0, []); //=> 0
reduce(add, 0, [1,2,3]); //=> 6
I see that you are trying to support a sort of reduce without an optional starting value. That is impossible if your reduce function is to be considered a total function. A starting value is required. Don't try to be clever.
Now a filter implemented using reduce
function filter(f, arr) {
return reduce(function(result, x) {
if (f(x))
return result.concat([x]);
else
return result;
}, [], arr);
}
Your examples
var myArray = [1,2,3,4,5];
filter(function(val){return val % 5 === 0;}, myArray)
//=> [5]
filter(function(val){return val <= 5;}, myArray)
//=> [1, 2, 3, 4, 5]
If you want to learn more...
There are other ways to implement reduce as well. One such improvement you could make is to put the recursion in tail position. When JavaScript engines support tail call elimination (with ES6), this would prevent reduce from stack-overflowing for significantly large values of arr.
function reduce(f, start, arr) {
function loop(result, arr) {
if (arr.length === 0)
return result;
else
return loop(f(result, arr[0]), arr.slice(1));
}
return loop(start, arr);
}
A blackhole appears...
With reduce and higher-order functions under your belt, you now stand at the shores of the deep, vast sea that is lambda calculus and functional programming. If you're feeling very zealous, you can explore how currying and combinators change this definition even more dramatically.
The following code is written in ES6
// U-combinator
const U = f=> f(f);
// Y-combinator
const Y = U (h=> f=> f (x=> h (h) (f) (x)));
// reduce
const reduce = f=> Y(h=> start=> arr=>
arr.length === 0
? start
: h (f (start) (arr[0])) (arr.slice(1)));
// filter
const filter = f=>
reduce(result=> x=>
f(x) ? result.concat([x]) : result) ([]);
// your examples again...
var myArray = [1,2,3,4,5];
filter (x=> x % 5 === 0) (myArray) //=> [5]
filter (x=> x <= 5) (myArray) //=> [1, 2, 3, 4, 5]
Why am i not hitting the last element of the array?
I don't know. It might be an error in your each-function, wich is not posted here. But since you have some more flaws in boh of your functions, I'll add a working implementation.
I've noticed that prev and curr actually never return 5 at any point of the reduce function.
prev and curr never return anything, they are arguments. And that particular function itself, also doesn't ever return anything.
First start === undefined is no proper check to determine wether yo want to initialize the result-value with the first(current)-element. undefined is an unexpected, even unwanted value in that place, but it is actually perfectly fine. So with that check, your reduce-function might start over again, in the middle of the collection.
Just take a look at the previously mentioned function you utilize in filter. This function does return undefined (as the value for the next iteration) ;) so that prev will always be undefined in your code.
Then, reduce makes no sense in your filter-function, at least the way you use it. You use it as each.
function reduce(collection, combine, start){
var result = start, hasValue = arguments.length > 2;
each(collection, function(element){
if(hasValue){
result = combine(result, element);
}else{
result = element;
hasValue = true;
}
});
if(!hasValue){
//no start/default-value, no elements in the collection,
//what result do you expect from this reduce-task?
throw new Error("reduce of empty array with no initial value");
}
return result;
}
function filter(collection, predicate){
return reduce(collection, function(result, elm){
//the functional-approach: no mutations
return predicate(elm)?
result.concat( [elm] ):
result;
//or a more sane way to do this in JS
if( predicate(elm) ) result.push( elm );
return result;
}, []);
}

Javascript: Write a function that takes in a number, and returns an array with that number in it that many times

I'm a complete newbie to programming and mathematical concepts (took Math 101 in college) so I'm struggling with this problem:
Write a function that takes in a number, and returns an array with that number in it that many times.
Here's the code I've got so far:
function numReturn(x) {
var newArray = [];
if (typeof x === "number") {
return newArray.push[x]* x;
} else {
return null;
}
}
Here's my thought process:
Create a function that can take in a number, x.
Within that function, create a blank array so you can push values to it later.
Check if the typeof value entered in for x is a number. If it is, return it pushed to the end of the blank array. Otherwise, return null.
When I put this in the Javascript console and plug a value in, it comes back undefined. Anyone have some pointers for me?
function a(i) {
var a = new Array(i);
return a.fill(i);
}
or return new Array(i).fill(i);, for short. Test:
a(4)
// --> [4, 4, 4, 4]
Array.prototype.fill() is an ES6 method and is not yet universally implemented. Chrome and Firefox have it, IE does not - but there is a polyfill available.
Compare: http://kangax.github.io/compat-table/es6/#test-Array.prototype_methods_Array.prototype.fill
In order to do something an arbitrary number of times, one uses a loop. There are several loops, but here the for loop is most appropriate.
A for loop has the following structure:
for(var i = 0; i < x; i++) {
// ^initializer
// ^condition
// ^increment
//body
}
The initializer is the first thing that is done when entering the loop. IN this case, it means a variable named i is set to 0. Then the condition x is checked. If the condition i < x holds, the loop is executed: the body is executed. After the body is executed, the increment is performed (here i++), and then the condition is rechecked, if the condition still holds, the loop is executed again, and so on.
You can apply this concept as follows:
function numReturn(x) {
var newArray = [];
if (typeof x === "number") {
for(var i = 0; i < x; i++) {
newArray.push(x);
}
return newArray;
} else {
return null;
}
}
This: newArray.push[x]* x does not push x times. The * operator just multiplies numbers, always and only. You want to push x times, so use a for like this:
for (var i = 0; i < x; i++ )
newArray.push(x);
and then return newArray.
Taking from answer of Most efficient way to create a zero filled JavaScript array?
function numReturn(x){
return Array.apply(null, Array(x)).map(Number.prototype.valueOf,x);
}
console.log(numReturn(10)); // [10, 10, 10, 10, 10, 10, 10, 10, 10, 10]
var n = 7
var result = Array.apply(null, {length: n}).map(function(){return n})
// Demo output
document.write(JSON.stringify(result))
As function:
function numReturn(x) {
if (typeof x === "number") {
return Array.apply(null, {length: n}).map(function(){return n})
} else {
return null;
}
}

Categories