Removing Values in Array using .splice() in Javascript - javascript

I'm attempting to loop through an array and remove any values that equal false, null, 0, undefined, NaN, or "".
When I call the function it should return a blank array but right now it's outputting [null,0,null,null,""]. Here's what I have so far.
function bouncer(arr) {
for(i=0;i<arr.length;i++){
if(arr[i]===false||null||0||undefined||NaN||""){
arr.splice(i,1);
}
}
return arr;
}
bouncer([false, null, 0, NaN, undefined, ""]);
Can anyone tell me what I'm doing wrong and why it is not removing these values from the array?

The problem is with this line:
if(arr[i]===false||null||0||undefined||NaN||""){...}
The correct way to compare for multiple values is:
if(arr[i]===false|| arr[i]=== null|| arr[i]=== 0||arr[i] === undefined|| arr[i] === NaN|| arr[i]=== ""){ ..}
You can simplify it further as all values we need to filter naturally evaluates to false
if(!arr[i])
Reimplementation of your function with the index adjusted for splicing:
function bouncer(arr){
for( var i = 0 ; i < arr.length ; i++ ){
if(!arr[i]){
arr.splice(i--,1);
}
}
return arr;
}
A better way to do this with immutability is by using Array.filter
function bouncer(arr){
return arr.filter((item) => (!!item));
}

You might want to read the javascript language syntax descriptions, again.
if(arr[i]===false||null||0||undefined||NaN||"") ...
means, if arr[i] is false, or null is true or 0 is true or undefined is true or NaN is true or "" is true. The first part depends on what arr[i] is, but the rest will all be false. That means we can simplify your statement, as written, to:
if (arr[i] === false) ...
Since the all the rest will always be false. But inferring what you want to do, you might want to say
if (arr[i] == false) ...
which will perform a looser, less rigorous comparison (i.e., it won't check the types of the elements being compared) and will test what I infer you want.
However, your logic has another problem: you are removing elements as you're iterating over the array, i is advancing as you are removing elements from under it. Another approach might be to build up the returned array (rather than modify the input array).
function bouncer(arr) {
var r=[];
for(i=0;i<arr.length;i++){
if ( arr[i] )
r.push(arr[i]);
}
return r;
}
Or better yet, use a method which is designed for the purpose of determining elements to keep (though it does not modify the original array, so you'll have to reassign it:
arr = arr.filter(function (elem) { return elem; });

mistakes:
Should be if(arr[i]===false||arr[i]===null||arr[i]===0||arr[i]===undefined||arr[i]===NaN||arr[i]==="")
Since NaN !== NaN, should use isNaN(arr[i])
if (...) {
arr.splice(i,1);
i--; // should minus one here!
}

Related

Looking for a function that takes three arguments (x, y, z) and checks if the type of all three is a string

Don't know what to put before the for loop. Don't know if I need an if/else statement. Trying to have it display in the console if items in an array are strings. So I know I need consol.log
var stringOne = isString('rob','bob','carl')
function isString() {
//I dont know what to put before for loop
for(let i = 0; i < arguments.length; i++) {
// Dont know if i need an if/else statement
// Trying to have it display in the console if items in an array are strings
// So I know I need consol.log
}
}
every would be appropriate here, and doing I/O (like console.log) is better left outside of the function. The name of the function suggests that it should return a boolean (true/false):
function isString(...args) {
return args.every(s => typeof s === "string");
}
console.log(isString('rob','bob','carl'));
Because it seems like you're a beginner, I will expand upon the code that you currently have, although #trincot did the best solution.
In a for loop, you can return a value so the loop won't continue. Because you only need to check if any of them are false, may it be in position 0, 1 or 2 in the array, you can return "false" immediately.
If there are only strings, the loop will continue until it ends, and then return "true" at the end of the method.
So you don't need any code before the for loop, only an if statement that returns "false" if any of the items in the array isn't a string.
var stringOne = isString('rob','bob','carl')
var stringTwo = isString('rob','bob', 1)
function isString() {
for(let i = 0; i < arguments.length; i++) {
if (typeof arguments[i] != 'string') {
return false
}
}
return true
}
console.log({stringOne});
console.log({stringTwo});
Something like this in the loop ought to do it:
this_arg = arguments[i];
if (typeof this_arg === 'string') console.log("arg number " + i + " is a string");
It shows how to do it a bit here
You may find every useful here. It iterates over the array you've made from the arguments and checks to see if each element matches the condition. If they all match it returns true, otherwise false.
function isString() {
return Array.from(arguments).every(str => {
return typeof str === 'string';
});
}
console.log(isString('rob','bob','carl'));
console.log(isString(2,'bob','carl'));

Am I using filter right? I don't know why this solution works

I'm going through FCC basic algorithms right now, and while I passed the exercise, I'm not fully understanding why it works, as when I change things to how I think they should be it doesn't work, but when I change things so they look wrong to me it still works.
For instance, I change true to false, and it still works, or I just type true, and it still works, or I just say return value, and it works. Does filter automatically remove falsy values?
Here is my code. My original code that didn't work said if (value === true).
function bouncer(arr) {
let x = arr.filter(value => {
if (value !== true)
return value;
})
console.log(x);
return x;
}
bouncer([7, "ate", "", false, 9]);
Remove all falsy values from an array.
Falsy values in JavaScript are false, null, 0, "", undefined, and NaN.
UPDATE
Thanks for all the answers, they were all super helpful in clearing up my confusion.
function bouncer(arr) {
let x = arr.filter(ages => {
return ages;
})
return(x);
}
bouncer([7, "ate", "", false, 9]);
This is the solution I ended up re-writing, and now understand why I did what I did.
Your callback,
if (value !== true)
return value;
is equivalent to just
return value;
in your case because none of the elements in your array are true, so value !== true always holds.
If you change it to
if (value !== false)
return value;
it still executes return value; for most array elements. The only exception is false, for which your function returns undefined (because no explicit return statement is executed). undefined is falsy, so it is treated the same as return false by filter (because filter only cares whether the callback returned a true or falsy value). So in the end not returning a value if the element is false is the same as return value.
On the other hand, if you change it to
if (value === true)
return value;
then your callback would return true if the current element is true and return undefined for any other value. The net effect is removing all elements that are not true (which in your case is all elements because your input array does not contain true).
If you want to remove falsy values, you can simply say
arr.filter(value => { return value; })
// or:
arr.filter(value => value)
because you're using the value itself as the condition: Anything that looks falsy is removed by filter; anything that looks true is kept.
If you find this confusing, perhaps looking at this custom (and simplified) filter implementation clears things up:
function my_filter(arr, fn) {
var results = [];
for (var i = 0; i < arr.length; i++) {
if (fn(arr[i])) {
results.push(arr[i]);
}
}
return results;
}
// Usage would be something like:
console.log(my_filter([7, "ate", "", false, 9], value => value));
If your purpose is to return an array that only retains the truthy values, then do this:
.filter(Boolean)
In your callback to filter you don't always return a value, and if you don't, that means the corresponding value will not be retained. Furthermore, with operators like !== and === you are doing a strict comparison. So value === true will only match true, not any other truthy value. Similarly, value !== true will still match some truthy values (that are not true).
filter iterates over your array. In each element iteration the callback is called.
If you return a "truthy" value in the callback that element is kept in the resulting Array, otherwise it's not.
Your confusion stems from the fact that you think you need to return the value argument in some way. You don't.
Look at this example:
var animals = ['dog', 'dog', 'cat', 'cat']
var cats = animals.filter(value => {
if (value === 'cat') {
return true
} else {
return false
}
})
console.log(cats)
Of course the above can be simplified to this:
var animals = ['dog', 'dog', 'cat', 'cat']
var cats = animals.filter(value => {
return value === 'cat'
})
console.log(cats)
That's just it.

Difficulty with Boolean and arrays in Javascript

Here, I am trying to write a code that takes a list of integers as a parameter and searches for the value 7. The function will return a boolean value representing true if 7 is in the list and false if it is not. This is what I have tried so far:
Could it be something with my else statement? Do I end it too soon? Or not soon enough?
You can simply use an array and use includes as per ECMA2016 like below:
if([2,5,7].includes(value)) {
return true;
}
return false;
or with list
var flag = false;
for(var i=0; i<arguments.length; i++)
{ if(arguments[i] == this) { flag = true; break; }}
return flag;
Javascript already has a function to do this. Array.prototype.includes(). You use it like this:
const containsSeven = list.includes(7)
If you are looking for something more complicated, like whether an item is an object and contains a particular key value pair for example, you can use Array.prototype.some()
Your declaration of the if statement is wrong. The else tag is on the wrong line. If you use else, it should come after the if-block.
But moving the else-block up, won't fix your function, because it will only return true if the first element in your array is a 7.
There are many good ways to do it, such as using higher order functions, but as it seems you are new to the language.
EDIT: Therefore, I would suggest one of the two simple ways below:
1) You could store the number of 7s found in the array in a for loop. Afterwards return false if the number of 7s is 0 or true if it the number is higher than 0
2) Another, much quicker way would be to return true in the for-loop when you encounter a 7 and after the for-loop just return false. Because a return statement exits the scope - which is your function - not only the for-loop would come to an end but also your function would return true much earlier.
For the second option, your function would look like this:
function find_value(list) {
for (let i = 0; i < list.length; i++) {
if(list[i] == 7) {
return true
}
}
return false
}
You can coerces to boolean the result of Array.prototype.find() which returns the value of the first element in the array that satisfies the provided testing function. Otherwise undefined is returned.
Code:
const list1 = [4, 5, 6, 7, 8];
const list2 = [1, 2, 3, 4, 5];
const findTheNumber = (arr, num) => !!arr.find(n => n === num);
console.log(findTheNumber(list1, 7));
console.log(findTheNumber(list2, 7));
Try this way
function search(list , value){ // Value = 7;
return true ? list.indexOf(value) > -1 : false
}

How to filter() out NaN, null, 0, false in an array (JS)

I was asked to filter out NaN, null, 0, false in an array.
Luckily I have answered the question.
function bouncer(arr) {
function filterer(arr) {
return arr > 0|| isNaN(arr) === true;
}
arr = arr.filter(filterer);
return arr;
}
//example input
bouncer([0, 1, 2, 3, 'ate', '', false]); //output [1, 2, 3, 'ate']
but the thing is I really don't know how I came up with the answer or rather I don't know how it works. Specially on arr > 0 how did the filter know that arr is alread on arr[1], arr[2], etc.. without using a loop to iterate in all array.
or can simply just explain on how to code works. [I've tried to explain it clearly ---]
If you were asked to filter out NaN, null, 0, false in an array, then your solutions doesn't really work.
Your input of:
bouncer([0, 1, 2, 3, 'ate', '', false, NaN]);
Will get the output of:
[1, 2, 3, 'ate', NaN]
To filter out all 'falsy' values you can simply use Boolean:
function bouncer(arr) {
return arr.filter(Boolean);
}
bouncer([0, 1, 2, 3, 'ate', '', false, NaN]);
Output:
[1, 2, 3, 'ate']
Since the Boolean constructor is also a function, it returns either true for ‘truthy’ argument or false for ‘falsy’ argument. If the value is omitted or is 0, -0, null, false, NaN, undefined, or the empty string (""), the object has the value of false. All other values, including any object or the string "false", create an object with an initial value of true.
You can also use an identity function instead of Boolean.
function bouncer(arr) {
return arr.filter(x => x);
}
I am also working on the Free Code Camp Falsy Bouncer Algorithm. I have found the simplest way to do it is:
function bouncer(arr) {
return arr.filter(Boolean);
}
Look at the docs for Array.filter. Notice in particular the arguments to the callback:
Function to test each element of the array. Invoked with arguments (element, index, array). Return true to keep the element, false otherwise.
So in your case arr is the element (and poorly named, hence your confusion). Filter loops through your array and for every item it calls you callback passing in the element at the current position as arr.
As others have pointed out in the comments, the logic of your filter callback is actually flawed for negative values, but that may not be an issue if you know that your array will never contain negative values (but that can be a dangerous thing to assume).
And, of course, internally, this is looping through your array. You can't filter your (unsorted) array without touching each element in the array. Look at the polyfil in the link to get an idea of how it might work (might because this is an implementation detail that may differ with different javascript engines, but will no doubt involve a loop somewhere), it loops through your array, calls the callback (note the arguments) and if the callback returns true, it gets pushed onto a results array.
The filter() method creates a new array with all elements that pass the test implemented by the provided function.
Since false, null, 0, "", undefined and NaN are all Falsy values in JavaScript therefore they will return false when tested.
function bouncer(arr) {
var array = arr.filter(function(val){
return val;
});
return array;
}
Only values which do not return false will be added to the array.
Wouldn't be more elegant to base on assumption that all unwanted elements are casted to false when boolean expected, so:
function clear (arr){
var stripped = [];
for (i = 0, len = arr.length; i < len; i++){
if (arr[i])
stripped.push(arr[i]);
}
return stripped;
}
Function to test each element of the array. Invoked with arguments
(element, index, array). Return true to keep the element, false
otherwise
If you just want explanation. Array filter() as name suggest. Remove unwanted element if condition falls wrong (false).
(arr > 0|| isNaN(arr) === true)
0, false || false //removed
1, true || false
2, true || false
3, true || false
'ate', false || true
'', false|| false // removed
false false || false //removed
Output:
[1, 2, 3, "ate"]
Since i´m a beginner o coding, my logic went to use primitive Boolean´s to compare the item´s
filtered, but this was before I have read the Boolean Object reference, you see is that
like its written there,
"The value passed as the first parameter is converted to a Boolean value if necessary. If value is omitted or is 0, -0, null, false, NaN, undefined, or the empty string (""), the object has an initial value of false. All other values, including any object or the string "false", create an object with an initial value of true."
So the logic since filter returns the value if it´s true or false, you should return values if
they are true.
Also, I didn´t learn everything about the filter method, for what I have researched, I have got
a bit more of information, that I will try to explain here.´
redefining the method (it already exists, is just for understanding)
the filter method accepts a function called
a predicate, that is a function that receives
a value and returns true or false.
The var results is an empty array where the results will be pushed with the push method.
The we use a forEach method with this, (this, in this context is applied to the array prototype ,this means that you will have the filter method available on every array that you define, with
the sintax of array.method(args) ins this case array.filter(args))
some resources
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/prototype
Now we will run an operation in every item on the the array, with the forEach method, now we will apply the predicate function to itch item of the array and if it returns true, will add it to the results.
Array.prototype.filter = function(predicate){
var results = [];
this.forEach(function(item) {
if (predicate(item)) {
results.push(item);
}
});
};
//-------------------------------Correct Solution---------------------------
function bouncer (arrToFilter){
return arrToFilter.filter(Boolean);
}
//----------Code without the filter method---------
function bouncerNoFilterMethod(arrToFilter){
var results = [];
arrToFilter.forEach(function(arrToFilter){
if(arrToFilter){
results.push(arrToFilter);
}
});
return results;
}
console.log(bouncerNoFilterMethod([7, "ate", "", false, 9]));
console.log(bouncerNoFilterMethod(["a", "b", "c"]));
console.log(bouncerNoFilterMethod([false, null, 0, NaN, undefined, ""]));
console.log(bouncerNoFilterMethod([1, null, NaN, 2, undefined]));
console.log(bouncer([7, "ate", "", false, 9]));
console.log(bouncer(["a", "b", "c"]));
console.log(bouncer([false, null, 0, NaN, undefined, ""]));
console.log(bouncer([1, null, NaN, 2, undefined]));
Hope this helps to understand, the method, and the first thing that was not understanding was the part of passing the function, the predicate to the method, if I have mistakes here please suggest corrections.
Looks like Boolean is the simplest fix/answer for the "FreeCodeCamp" challenge, however it might be useful to try a couple of things just to get the hang of "why" and "how".
function bouncer(arr) {
return arr.filter(function(val){
return val;
});
}
This evaluates everything passing through the filter, using the function(callback) passed in, which returns values. If it doesn't return a value, which null etc won't, it won't be included in the return. At least this method helped me understand why rather than just pass the test.
I slightly modified https://stackoverflow.com/a/35327425/3932895 to set everything to zero that has no numerical value
function zerofy(x){return (Boolean(x) && !isNaN(x.toString())) ? x : 0 ;}
Tested with
function clear (arr){
var stripped = [];
for (i = 0; i < arr.length; i++){
stripped.push(zerofy(arr[i]));
}
return stripped;
}
in
clear(["written",13,0,-4,"5",true,false,undefined,null,NaN,Math.PI]);
results to
[0,13,0,-4,5,0,0,0,0,0,3.141592653589793]
function bouncer(arr) {
// Don't show a false ID to this bouncer.
function isFalsyBouncer(value){
if(Boolean(false)||Boolean(null)||Boolean(0)||Boolean("")||Boolean(undefined)||Boolean(NaN)){
}else{
return value;
}
}
var filtered=arr.filter(isFalsyBouncer);
return filtered;
}

Check array for multiple values in specific order

I have this array (below) and I'm trying to check if it has specific values.
var a = [ true, "lipsum" ];
What I need to do, is to check if a[0] is true and if a[1] is "lipsum"
I could check both values separately:
a[0] === true && a[1] === 'lipsum' // true
...to shorten the code a bit, I tried to do this:
a === [ true, 'lipsum'] // false
Why is this code example above false and is there another way to achieve what I'm trying to do?
I could do this:
a.join() === 'true,lipsum' // true
though I can't help but feel that there is a better way..?
jsfiddle
For only two elements to check the straightforward way seems best, but I assume you want to do this for maintenance reasons because eventually you may have several conditions to check (not just two). If so, you can do something like the following, which seems verbose for only two conditions, but as you start adding more it would be more reasonable, so here's an example with 5 conditions to check:
// set a constant somewhere for your truth condition
var COND = [1, 'a', 5, 'b', 0];
// check `a` against the constant array using `every` (Thanks Bergi)
if (a.every(function(v, i){ return COND[i] === v; })) {
// all array elements the same
}
Each array is a separate object, so the equality operator cannot be used to compare them. Assuming that you have a strict comparison of known arguments to do, the first method you use is the best.
If you have another array of arguments that the original array must contain, you must use a loop, although you could abstract it:
Array.prototype.contains = function (array) {
for (var x = 0; x < array.length; x++) {
if (this.length < x || this[x] !== array[x]) {
return false;
}
}
return true;
}
http://jsfiddle.net/q5DvG/1/

Categories

Resources