im a JS newbie. Trying to figure out this problem below. I am stuck on the "if" statement and not sure exactly what to put in. Also im not sure if my "push" is setup right
// Define a function named `compact` that accepts an array and returns
// another array with all the falsey values removed from it. For example,
// if this array was passed in:
// [1, 4, 0, '', undefined, false, true, null, {mj: 'mj'}, 'Hello']
// the function would return this, as a result:
// [1, 4, true, {mj: 'mj'}, 'Hello']
var compact = function (array) {
var truthyValues = [];
for (var i = 0; i < array.length; i += 1) {
if () {
truthyValues.push[i];
}
}
return truthyValues;
};
You're close. Here's what the if should be:
if (array[i]) {
truthyValues.push(array[i]);
}
Since you want to check for truthiness of each array element, just put array[i] in the if block. That gets the value of the array at i, and will evaluate as true if that value is truthy.
Then push not i - the index into array - but array[i], so that the actual value is in truthyValues.
Just put the value you want to check is truthy in the if statement, since the if statement checks for truthiness.
if(array[i]){
truthyValues.push(array[i]);
}
I think you can just use:
if (array[i]) { truthyValues.push(array[i]); }
Values like null will trigger false.
if (typeof array[i] !== "undefined" && array[i] !== null) {// push to array // }
most of these other answers will not work for falsy and existy values. You'll need to define what you intend to be existy and write a helper function for that. you could use the one I provided as a start and then roll your own.
Related
I am trying to create a function to check whether two arrays are deeply equal to each other.
An example would be: [1, 2, { a: "hello" }] and [1, 2, { a: "bye" }] would return false.
This is my code so far:
const deeplyEquals = (val1, val2) => {
let counter = 0;
for (var i = 0; i < val1.length; i++) {
if (typeof val1[i] === "object") {
deeplyEquals(JSON.stringify(val1[i]), JSON.stringify(val2[i]));
} else if (typeof val2[i] === "object") {
deeplyEquals(JSON.stringify(val1[i]), JSON.stringify(val2[i]));
} else if (val1[i] !== val2[i]) {
counter++;
}
}
return counter === 0 ? true : false;
};
I implemented a counter so that if it found a value in 1 that was not equal to the same value in 2 then it would increment. If the counter was not 0 then it would return false.
For the example, the counter increments to 7 but then right at the end, changes to 0 and therefore returns true instead of false.
I'm sure there would be an easier way to do this but I was wanting to see whether I could make this work as I am unsure why the counter is changing to 0 right at the end.
Thanks for any help!
The problem is that the counter is local to each call to deeplyEquals. There's a different counter for each call, and since you're making the calls recursively, you have lots of different counter variables in memory at the same time.
If you wanted to maintain a counter, you'd have to have each recursive call return the counter value (instead of a flag) so the code calling it could increment its counter by that much.
But there's no need in your code. Instead, just return false the first time you find a difference, either during in the call itself or in one of its recursive calls by checking the return value of the recursive call.
There are other issues with the code. Here's what I notice off-the-cuff:
You're calling JSON.stringify, which returns a string, before passing values to deeplyEquals, which will convert arrays and objects to strings. Comparing the strings won't be reliable (because equivalent objects can have their properties in different orders: JSON.stringify({a:1,b:2}) is the string {"a":1,"b":2}, but JSON.stringify({b:2,a:1}) is the string {"b":2,"a":1}). Instead, pass the actual value.
typeof x returns "object" for arrays and null as well as non-array objects; you need to handle those three cases separately.
When comparing non-array objects, you need to loop through their properties to compare them.
SO has several questions and answers about doing deep equality checks; probably best to search for those, study them to ensure you understand how they work, and go from there.
Why dont you just JSON stringify both arrays and then compare?
const deepEquals(val1, val2){
let v1 = JSON.stringify(val1);
let v2 = JSON.stringify(val2);
return v1 === v2;
}
I'm following an online course about Javascript Functional Programming
at the Exercise 16 it show you how reduce is actually implemented, in order to help you understand how to use it, but into this implementation there is something i don't actually get, i'll show the code:
Array.prototype.reduce = function(combiner, initialValue) {
var counter, accumulatedValue;
// If the array is empty, do nothing
if (this.length === 0) {
return this;
}
else {
// If the user didn't pass an initial value, use the first item.
if (arguments.length === 1) {
counter = 1;
accumulatedValue = this[0];
}
else if (arguments.length >= 2) {
counter = 0;
accumulatedValue = initialValue;
}
else {
throw "Invalid arguments.";
}
// Loop through the array, feeding the current value and the result of
// the previous computation back into the combiner function until
// we've exhausted the entire array and are left with only one value.
while(counter < this.length) {
accumulatedValue = combiner(accumulatedValue, this[counter])
counter++;
}
return [accumulatedValue];
}
};
I don't understand the first if statement, when it check for this.length what this actually mean?
Take note this is different from the reduce in ES5, which returns an value instead of an Array, this is used just as a sample for the learning purpose.
Array.prototype.reduce = function(...
is saying, "create a function on the prototype of Array" - this means that the new reduce function will be callable on all arrays, eg:
[1, 2, 3].reduce(...
This means you can also call it on empty arrays, eg:
[].reduce(...
Building on the comment:
If the array is empty, do nothing
You're working on an array, and when the function is called, this is set to the array that reduce was called on. This implementation of reduce assumes that if that array is empty (ie this.length === 0), you can't logically reduce it any further - there's nothing to reduce, so you can return the same empty array.
As pointed out by #Alnitak in the comments, this implementation of reduce is flawed as compared to the specification. A different implementation is available on the MDN for polyfilling older browsers.
Im trying to get a sum of array injected into a function that loops until all the values are added, the console.log right before the "return" logs the right value, meaning the code works, but when I try to use that function with any array it returns "undefined"...
var total = function(arr) {
console.log(arr);
if(arr.length > 1) {
var temp = []
for(var i=0, len=arr.length-1; i<len; i++) {
temp.push(arr[i] + arr[i+1]);
}
total(temp);
}
else {
console.log(arr.join()); // 48, exectly what I need
return parseInt(arr.join());
}
}
var sup = total([1,2,3,4,5]); // undefined
Not completely sure how to debug it..
If your arr.length is greater than one, you will invoke total with the temporary array, however, you don't do anything with this temporary array - you don't return it, or utilize it in any way, so the intermediate results are lost.
In addition - this is not a self invoking function; it is recursion.
This question already has answers here:
How do I test for an empty JavaScript object?
(48 answers)
Closed 8 years ago.
As title says, I have the following array:
var viewModel = [{}, {}, {}];
At some point in my code I may populate the 2nd element:
var viewModel = [{}, { "test" : "value" }, {}];
I need a way of evaluating if the elements are empty or not. In the above case, elements 0 and 2 will evalute to true, and element 1 will evaluate to false.
What I've Tried
I've tried comparing each element to undefined and ' ' to no avail. I know could probably check for the test property of each element (if it exists it's not empty) but I ideally wanted a way of determining this independent of any property names.
(I've tagged jQuery as I'm open to jQuery suggestions).
{} === {} //false
JSON.stringify({}) === JSON.stringify({}) //true
JSON.stringify(myArray[0]) === JSON.stringify({}) //true
This might come handy in your particular case may be. I havent thought much about the loopholes also.
How about this
// function to check if object is empty
function isEmpty(obj) {
return Object.keys(obj).length === 0;
}
var viewModel = [{}, { "test" : "value" }, {}];
// loop
for(var i = 0; i < viewModel.length; i++)
{
// returns true if empty, otherwise false
console.log(isEmpty(viewModel[i]));
}
You can count the elements that are in each object by looping through the array.
for(var i = 0; i < test.length; i++){
if(Object.keys(test).length == 0){
//element array[i] is empty!
}
}
This is only in browsers supporting Ecma-script 5.
Takes an array of objects and returns a new array of true/false values
function isObjectEmpty(arr) {
return arr.map(function (el) {
return Object.keys(el).length === 0 ? true : false;
});
}
isObjectEmpty(yourExampleArray) // [true, false, true]
Demo
When having a simple boolean, it is simple to use it in a condition :
var running = true;
if(running) {/*do something*/}
Is there some trick to do this with a boolen array? something like this:
var running = [false,false,true,false];
if(running[]){/*do something*/}
At the moment I do it like this :
var uploading = false
for(i=0; i< running.length ; i++)
{
if(running[i]) uploading = true;
}
if(uploading)
But I feel like this is not really perfectly written code and that their could be some trick, shorthand method.. Could be plain javascript, could be Jquery
jQuery has the $.inArray method:
uploading = $.inArray(running, true) !== -1;
The name is slightly misleading, it returns the index of the element that matched (-1 if none).
JavaScript has Array#indexOf, but it's missing in IE8 and earlier:
uploading = running.indexOf(true) !== -1;
JavaScript as of ES5 has the Array#some method, but it's overkill if you can look for the specific value with either of the above. Still, it's useful if you need to massage the values at all. For instance, if any "truthy" value is okay rather than specifically true:
uploading = running.some(function(entry) { return !!entry; });
You can just use this:
uploading = running.indexOf(true) !== -1;
If the array doesn't contain a true, indexOf will return -1, resulting in a false from !== -1. If the array contains a true, indexOf will return it's index, resulting in a true.
A slightly shorter option:
uploading = !!~running.indexOf(true);
The ~ is a bitwise NOT, this inverts the value from indexOf: -1 -> 0, 0 -> -1, 1 -> -2, etc. Then the double ! first casts this value to a boolean, then inverts it again, resulting in a boolean output that's true then the array contains a true.
I just thought about little trick that can work in this situation:
uploading = !!Math.max.apply(null, [false, true, false, false]); // => true
Basically without !! path you will get 1 (if there is at least one true) or false (for all false in array). Max calls ToNumber for each passed argument, so true => 1.
Note: you'd better use indexOf, this is just for fun and to demonstrate another unobvious way.