I am trying to test if an array is sorted in ascending order using the JS every method: checking if every element is smaller than the next index.
I don't understand why my code below is not working.
const testArray1 = [1, 2, 3, 4, 5, 6];
const testArray2 = [25, 51, 32, 12, 15];
const isAscending = (element, index, array) => {element < array[index + 1]};
console.log(testArray1.every(isAscending));// expecting true, but getting false
console.log(testArray2.every(isAscending));// expecting false, getting false
I am aware that the sort method exists, this is for a school exercice.
You have two problems.
Your arrow function always returns undefined because it is missing a return statement.
You are comparing the last value in the array to undefined (e.g. when i is 5 for the first array, element is 6 and array[5 + 1] is undefined) which is always false so you need to implement a special case for that entry.
Why filter method can't work with ternary conditional as it works with if conditionals ?
In case it works with if..else
let numbers = [-1, -2, -3, 1, 2, 3];
let negatives = [];
let positives = numbers.filter(num => {
if(num > 0) {
return num; // positives array => [1, 2, 3]
} else {
negatives.push(num); // negatives array => [-1, -2, -3]
}
})
In case it works with ?
let positives = numbers.filter(num => num > 0 ? num : negatives.push(num));
// positives array => [-1, -2, -3, 1, 2, 3]
// negatives array => [-1, -2, -3]
I tried filter method with if conditionals and it returns the result as I expect. but what is not expected for me the result when it works with ternary conditional.
The issue is that you are misunderstanding what the code you pasted does.
Let's see.. in the first code, the fitering function returns either num or nothing (after negatives.push() there is no return, so it implicitly returns undefined).
function fn(){
// no explicit return
}
const what = fn();
typeof what === "undefined"; // true
The second version, returns either num or the returned value of negatives.push() call, which is by definition:
Return value
The new length property of the object upon which the method was called.
So in the second version of the code, the filter receives for every negative number: 0, 1, 2... and so on. The first occurrence will be taken as a "falsy" (0 is a "falsy" value in JS) so it will be filtered out from the resulting array, the following negative numbers will be included in the resulting array as the filtering function will return "truthy" values for them (positive numbers are "truthy" values in JS)
Being that said...
It is a bad practice to use a filter function for other task than filtering things.
In this scenario where you need to separate positives from negatives, use forEach which is more clear and appropriate.
const positives = [];
const negatives = [];
numbers.forEach(num => {
if(num > 0) { // Note: that this comparison will send ZEROES to negatives array, which could lead to a bug.
positives.push(num);
} else {
negatives.push(num);
}
});
or simpler:
const positives = [];
const negatives = [];
numbers.forEach(num => (num > 0 ? positives : negatives).push(num));
The array method filter expects a callback which returns a boolean value. In your second example you are returning num when num is positive (which is truthy).
However, when num is negative, the method returns the result of negatives.push(num) which is also truthy.
I'm trying to understand how filter() and includes() work with arrays in javascript but english isn't my native language so I would really appreciate it if someone could explain the example below to me like I was 5:
const removeFromArray = function(...num) {
let array = num[0];
return array.filter(val => !num.includes(val))
};
This function takes an array and some other arguments then removes the other arguments from that array for example removeFromArray([1, 2, 3, 4], 3) should remove 3 and return [1,2,4]
How does this part work?
return array.filter(val => !num.includes(val))
Why the exclamation mark and also how do those two methods work together?
I think the key to understanding what is going on is the parameter(s) of the function, num. The code uses a nice trick that I have not encountered before. So, num is:
[[1, 2, 3, 4], 3];
a 1D array with TWO elements: [1, 2, 3, 4] at index 0, and 3 at index 1. As a result:
num.includes([1, 2, 3, 4]) // is true
num.includes(3) // is true
num.includes(anything-else) // is false
The
Array#includes
method determines whether an array includes a certain value among its
entries, returning true or false as appropriate.
In the simplest form, whenever a boolean expression is prefixed with !, the result of the expression is negated. For example:
!num.includes(3) // becomes false
The
Array#filter
method creates a new array with all elements that pass the test
implemented by the provided function.
Pass the test simply means return true.
Now we are ready to look at num[0].filter(val => !num.includes(val)). Or:
[1, 2, 3, 4].filter(val => !num.includes(val))
Please recall that ONLY 3 and [1, 2, 3, 4] return true to:
num.includes(val)
Hence of all the elements of num[0] or [1, 2, 3, 4] only 3 returns false to the negated expression:
!num.includes(val)
1, 2, and 4 return true or !false, meaning that they pass the test and hence will be returned by the function:
[1, 2, 4];
Please note that val => !num.includes(val) is a shorthand way of writing:
function( val ) {
return !num.includes(val);
}
const removeFromArray = function(...num) {
let array = num[0];
return array.filter(val => !num.includes(val))
};
console.log( removeFromArray([1, 2, 3, 4], 3) );
Rest parameters shouldn't be used like that, it should only be used for like values. So, the array should be accepted separately and only the numbers to remove should be accepted using rest (refer to the snippet below).
The includes() method determines whether an array includes a certain value among its entries, returning true or false as appropriate.
So, we simply filter out numbers that are not present in the itemsToRemove array.
const removeFromArray = (array, ...itemsToRemove) =>
array.filter((item) => !itemsToRemove.includes(item));
removeFromArray([1, 2, 3, 4], 3, 2);
! means "not". If something is falsy (null, 0, false, an empty string), then !something returns true. This leads to a really strange looking "cheat code" where you can convert any value to a boolean (i.e. truthy to true and falsy to false) via !!value. One exclamation point converts it to a boolean value that's true if value is falsy, then the second exclamation point changes true to false (or false to true)!
array.prototype.filter requires a function to be evaluated against each element and returns an array of only the elements where the supplied function returns a truthy value.
It might be easier to think of the following code that is nearly equivalent to yours...
const removeFromArray = function(array, ...valsToRemove) {
const isValToKeep = val => array.includes(val) === false;
return array.filter(isValToKeep)
};
The only difference in this code, besides being longer, is that the first argument won't be looked for within the first argument. Consider
const a1 = [1,2,3];
a1.push(a1); // appends itself as its last element
In your version, removeFromArray(a1, 2) would return [1, 3], but mine doesn't combine the first argument as one of the elements to look for and remove from the first argument, which is probably what most people would expect and be more performant, but would definitely have a different effect in the example returning [1, 3, a1], i.e. [1, 3, [1, 2, 3, [1, 2, 3, [1, 2, 3, [1, 2, 3, [1, 2, 3, [1, 2, 3, [...]]]]]]]]
This is a simple form to explain how to use filter
function isBigEnough(value) {
return value >= 10;
}
var filtered = [12, 5, 8, 130, 44].filter(isBigEnough);
// result is [12, 130, 44]
This example is from: https://developer.mozilla.org/pt-BR/docs/Web/JavaScript/Reference/Global_Objects/Array/filter
Lets start by rewriting this line:
Before
return array.filter(val => !num.includes(val))
after
const callback = val => {
return !num.includes(val)
}
const filteredArray = array.filter(callback);
return filteredArray
Now lets break and explain parts of this statement:
! num.includes(val)
includes method here will check if num has val in it. If num has val it will return true else it will return false. note the ! at the begining of the line ,that will change the value returned by includes to its opposite e.g if value returned is false it will change it to true if value returned is true it will change it to false.
array.filter(callback)
The filter method here will go through every element of the array and at each element it will ask whether to add that element to the filteredArray or not based on what is returned from the callback. If callback returns true(truthy) it will add it else it will not add it. The callback should only return true(truthy) or false(falsy).
example :
At index 0 of array the filter will ask did callback return true if it returned true the element at index 0 will be added to the filtered array. It will do the same for the rest of the elements.
How they work together:
array has [1,2,3,4] so array.filter(callback) will go over each element and call callback on each. Based on your function num has this [[1,2,3,4],3] so when val from array is 3 !num.includes(val) will return true but this ! will change it to false as a result callback will return false and 3 will not be included in the final array the filteredArray.
Hope a 5 year old can understand this explantion. You can now rewrite your function like this :
const removeFromArray = (array, ...numbersToRemove) => array.filter((number) => !numsToRemove.includes(number));
I have an array with integers in it; and a function that returns a string. In this example, the function returns either 'solved' or 'unsolved', based on the fact if a specific task was done before or not.
Now I need a way to call my function with every array element as parameter and check if the function returns 'solved' for every element.
Small example with real values:
var array1 = [2,5,8]; // 2 is solved, 5 is solved, 8 is unsolved
var array2 = [2,5,6]; // every element is solved
if (Function returns solved for every element) {
// array2 would be accepted for this part
}
else {
// array1 would go in this branch
}
Array.prototype.every()
The every() method tests whether all elements in the array pass the test implemented by the provided function.
If you already have a function that returns a string (i.e. 'solved' or 'unsolved'), then you can simply convert that to a boolean inside the callback you supply to .every().
var array1 = [2, 5, 8]; // 2 is solved, 5 is solved, 8 is unsolved
var array2 = [2, 5, 6]; // every element is solved
function isSolvedString(operand) {
return operand < 8 ? 'solved' : 'unsolved';
}
function isSolved(current) {
return isSolvedString(current) === 'solved' ? true : false;
}
console.log(array1.every(isSolved)); // false
console.log(array2.every(isSolved)); // true
It appears that the reduce method of underscore.js assumes that the 'memo' value is a scalar, whereas Ruby will accept a general object. Would this be a bug, a limitation of underscore.js or am I somehow screwing up?
Here is a trivial example of reduce in Ruby 1.9.3.
irb(main):020:0> a = [1, 1, 2, 2]
=> [1, 1, 2, 2]
irb(main):021:0> a.reduce([]) {|accum, nxt| accum.push(nxt)}
=> [1, 1, 2, 2]
Here is what I believe to be the equivalent code using _.js
var _ =Underscore.load();
function tryReduce() {
var a = [1, 1, 2, 2]
var b = _.reduce(a, function(out, nxt) {
return out.push(nxt);
}, [])
Logger.log(b)
}
In Google Script the code bombs with
TypeError: Cannot find function push in object 1. (line 6, file "tryingStuff")
However this code runs and gives the correct result, 1006.
var _ =Underscore.load();
function tryReduce() {
var a = [1, 1, 2, 2]
var b = _.reduce(a, function(out, nxt) {
return out + nxt;
}, 1000)
Logger.log(b)
}
The issue is that Array#push returns different values in each language. While Ruby's returns the Array itself, JavaScript's returns the updated length.
_.reduce() can work with Array memos, but you have to ensure that the Array is what's returned in the iterator:
var b = _.reduce(a, function(out, nxt) {
out.push(nxt);
return out;
}, [])
Otherwise, the 1st round ends with a Number (the length) and the next round throws an error since Number#push doesn't exist. This is the "scalar" you mentioned:
It appears that the reduce method of underscore.js assumes that the 'memo' value is a scalar