I'd like to filter an array of objects based on multiple tests. For this example, I want to filter an array of objects if the values for the keys aren't null, and that one value for one key is less than 90. I'm currently doing this with a for loop like so:
let filtered = []
for (let i = 0; i < articles.length; i++) {
if (articles[i].title !== null && articles[i].title.length <= 90 &&
articles[i].date !== null &&
articles[i].image !== null &&
articles[i].description !== null &&
articles[i].link !== null) {
filtered.push(articles[i])
}
}
But it's pretty clumpy and I know the filter method can achieve something similar. But I'm unsure if it can check multiple keys and their values with the same test whilst checking if a specific value passes an independent test too.
Try:
articles.filter(article =>
Object.values(article).every(x => (x !== null))
&& article.title.length <= 90
)
Let's break this down:
articles.filter(article => ...)
.filter is a function property of type that accepts a callback argument, which it calls for each item. Essentially, we're passing it a function - not executing it right away, which it can call at its leisure. It's sort of like:
let a = alert;
We're not calling the alert function, we're just saving it to a variable. In the case of .filter, we're using it as a pseudo-variable - an argument. Internally, all .filter is doing is:
Array.prototype.filter(callbackFunc) {
newArr = [];
for (i=0;i<this.length;i++){
if (callbackFunc(this[i]) === false){ // We're calling `callbackFunc` manually, for each item in the loop.
newArr.push(this[i]);
}
}
return newArr;
}
The next bit to explain is the actual callback function we're using. It's defined with ES6 arrow syntax, but it's the equivalent of:
articles.filter(function(article){
return Object.values(article).every(x => (x !== null))
&& article.title.length <= 90
})
The first line of the callback function, Object.values(article).every(x => (x !== null)), can be broken down to:
let values = Object.values(article); // Get the value of all of the keys in the object
function checkFunction(item){ // Define a helper function
return (x !== null); // Which returns if an item is _not_ null.
}
let result = values.every(checkFunction); // Run `checkFunction` on every item in the array (see below), and ensure it matches _all_ of them.
Finally, we just need to clarify what every does. It's another example of functional JS, where functions accept callback functions as parameters. The internal code looks like this:
Array.prototype.every(callbackFunc) {
for (i=0;i<this.length;i++){
if (callbackFunc(this[i]) === false){ // We're calling `callbackFunc` manually, for each item in the loop.
return false;
}
}
// In JS, returning a value automatically stops execution of the function.
// So this line of code is only reached if `return false` is never met.
return true;
}
And && article.title.length <= 90 should hopefully be self-explanatory: while .every returns a boolean value (true or false), a true will only be returned by the callback function to the filter if the second condition is also met, i.e if the every returns true and article.title.length <= 90
The filter method does exactly this: it takes a conditional (just like that in your if statement and adds it to the array if the condition is met. Your code almost matches the filter syntax exactly, actually:
let filtered = articles.filter(article =>
article.title !== null
article.title.length <= 90 &&
article.date !== null &&
article.image !== null &&
article.description !== null &&
article.link !== null);
yes filter can do this, it just takes a function and applies it to each item in the array
array.filter(x => x.title != null && ... etc)
the examples in this section is pretty much what you are doing https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/filter#Filtering_invalid_entries_from_JSON
I've got an array that has a lot of objects and embedded arrays. I need to iterate through the entire array to see if anything is empty or null. My problem is checking Arrays and whether or not the arrays return empty. I keep getting object arrays and they are not null or undefined so get added in even if length is 0. What I've got so far.
var progressCount = 0;
var progressKeyLength = progressBarCriteria.length;
for (var i = 0; i<progressKeyLength; i++){
//I can find the arrays here but still not able to check length since they are actually object arrays.
if(Array.isArray(progressBarCriteria[i])){
console.log('array' + i);
}
if (progressBarCriteria[i] !== null && progressBarCriteria[i] !== ""){
++progressCount
}
}
progressBarCritiria = [
example1: "",
example2: "asdasdas",
example3: 233,
example4: {asda: 1},
example5: {asadasda: "asdasdA"},
example6: "",
example7: [],
example8: [1, 12312],
example9: [{1: "ad"}, {1: 12312}],
]
So 1, 6 and 7 should not be added to my count.
If you need to check the length or null value for an array, you can think about the Truthy - Falsy value as follow:
if (Array.isArray(progressBarCriteria[i]) && progressBarCriteria[i].length) {
// This is an array and is not empty.
}
This Array.isArray(progressBarCriteria[i]) checks if that value is an array.
If this progressBarCriteria[i].length is 0 the boolean value will be false, ortherwise will be true.
You can use a recursive function to do that. It is important to notice that in javascript arrays are objects. So you need to check for objects by if (typeof arr === 'object' && !(arr instanceof Array)). For more informations check this and this.
function recursive_array_chekc (arr) {
//check if arr is an object
if (typeof arr === 'object' && !(arr instanceof Array)) {
//check if object empty
if (Object.keys (arr).length === 0) {
//do something if empty
console.log ('this object is empty');
} else {
//check object properties recursivly
for (var key in arr)
if (arr.hasOwnProperty (key))
recursive_array_chekc (arr[key])
}
} else
if (Array.isArray (arr)) {
//check if array is empty
if (arr.length === 0) {
//do something if empty
console.log ('this array is empty');
} else {
//check array elements recursivly
for (var i = 0; i < arr.length; i++)
recursive_array_chekc (arr[i])
}
}
}
I was able to look at both answers and came up with this working solution. This is using Typescript so sorry for confusion.
for (var i = 0; i<progressKeyLength; i++){
if (!(progressBarCriteria[i] instanceof Array)){
if(progressBarCriteria[i] !== null && progressBarCriteria[i] !== "") {
++progressCount
}
} else {
let current = progressBarCriteria[i];
if (Array.isArray(current) && current.length !== 0){
++progressCount
}
}
}
if (myArray contains only myObject) {
//Do stuff...
} else {
//Do different stuff...
}
What should I do to make the if (myArray contains only myObject) line actually check if myArray contains only myObject?
The object will not be in the array more than once and will be in position 1 (not position 0) only. So, using myArray.length won't help (maybe?).
I'm using .splice to add an object into myArray at position 1 so position 0 should be undefined.
Based on your question i can only deduce the following are what you want
A particular object shouldn't be in the array more than once.
The Length of the array shouldn't be greater than 2, which will
answer that you maybe only want an object in the array but the first
element can be undefined tho.
A proper way to do this will be:
let myArray = [undefined, "object", "object"];
//check that myArray only contains "object"
//1: The "object" should not be in the array more than once
//2: I presume you also want the array length not to be greater than 2
console.log(containsObjectOnly("object", myArray));
function containsObjectOnly(obj, myArray) {
var isOnly = false;
let xTimes = 0;
let found = myArray.filter((value) => {
if (value == obj && xTimes === 0) {
isOnly = true;
xTimes++;
} else if (xTimes > 0 && value == obj) {
isOnly = false;
}
return isOnly;
});
return isOnly && !(myArray.length > 2);
}
you want to check two conditions:
first, the length of the array can only be 2 (since we have the object at instance 1)
second, the first index must be undefined.
so
if(myArray.length ==2 && myArray[0] === undefined &&(myArray[1] == myObject)){
//some code
}else{
//some other code
}
edit: just a note, we can still take advantage of the array length since we know that the index we set is [1]
ie. [undefined,{our object}];
if (myArray.length === 1 && JSON.stringify(myObject) === JSON.stringify(myArray[0])) {
console.log("myObject is in here, and it's the only element!");
}
else {
console.log('nope!');
}
The following function takes an object, loops through each value and returns false if the object or its children have an empty or undefined property web. Otherwise, it returns true:
hasNoCategories (object) {
for (let key in object) {
const value = object[key]
for (let i = 0; i < value.length; i++) {
const item = value[i]
if (item.web !== undefined && item.web !== '') return false
}
if (key === 'web' && value !== '') {
return false
}
}
return true
},
Example input:
{
"livingroom": [],
"garage": [],
"outdoors": [],
"other": [],
"id": "ZI4hteKxgr",
"name": "Cuiti",
"description": "",
"user": "",
"date": "2016/5/13",
}
How to rewrite this function without using for loops?
I'm not 100% sure what you expect the code to do, because your existing code and your description differ.
Your description is, rephrased, that this function checks whether object.web or any object.XXX.web are undefined. Your code however assumes that all members are arrays and checks whether object.web or object.XXX[YYY].web are undefined. (Note that it also doesn't do it correctly and accesses .length even though the member in question might be undefined.)
Since I'm not sure which of those is right, I'm providing two answers.
Functionality as per your textual description:
function hasNoCategories(object) {
if(!object.web) return false;
return Object.keys(object).every(function(key) {
if(typeof object[key] !== 'object') return true;
return !!object[key].web;
});
}
Functionality as per your existing code: (but with the length property access fixed)
function hasNoCategories(object) {
if(!object.web) return false;
return Object.keys(object).every(function(key) {
if(!Array.isArray(object[key])) return true;
return object[key].every(function(el) {
if(typeof object[key] !== 'object') return true;
return !!el.web;
});
});
}
To understand how this works, check out the documentation on Object.keys (which returns an array with the names of all keys in your object) and Array.prototype.every (which runs a callback function for every element in an array and returns true only if the callback returned true for every element).
Note that I'm assuming that your "empty or undefined" should reject all kinds of falsy values including null and the number (not string) zero. If not, then all the checks like if(!something) and return !!something would need to be changed to if(typeof something === "undefined" || something === '') and return typeof something !== "undefined" && something !== '', respectively.
Side note to prevent nitpicking: Of course there are still loops going on. But it was specifically asked "without for loop" and there is no for in this code.
I assume this is what you are looking for:
var hasNoCategories = function(object) {
if (!object.web) {
return false;
}
for (let key in object) {
var value = object[key];
if (!value.web) {
return false;
}
}
return true;
};
I got rid of 1 loop. But this cannot be done without loops because you have to loop over all children. You can hide this loop inside some another function but you cannot get rid of it.
If you really don't want to use loops (I don't know why), one of your options is to serialize the object and phrase the string for the word "web".
var s = JSON.stringify(object);
var webIndex = s.indexOf('web');
Now perform some checks around this index to ascertain if that has the value 'undefined' or ''. Please keep in mind that the word "web" can match as a part of another property name too. So, you need to include this possibility too to your checks.
When the page is loading for the first time, I need to check if there is an image in image_array and load the last image.
Otherwise, I disable the preview buttons, alert the user to push new image button and create an empty array to put the images;
The problem is that image_array in the else fires all time. If an array exists - it just overrides it, but alert doesn't work.
if(image_array.length > 0)
$('#images').append('<img src="'+image_array[image_array.length-1]+'" class="images" id="1" />');
else{
$('#prev_image').attr('disabled', 'true');
$('#next_image').attr('disabled', 'true');
alert('Please get new image');
var image_array = [];
}
UPDATE
Before loading html, I have something like this:
<?php if(count($images) != 0): ?>
<script type="text/javascript">
<?php echo "image_array = ".json_encode($images);?>
</script>
<?php endif; ?>
if (typeof image_array !== 'undefined' && image_array.length > 0) {
// the array is defined and has at least one element
}
Your problem may be happening due to a mix of implicit global variables and variable hoisting. Make sure you use var whenever declaring a variable:
<?php echo "var image_array = ".json_encode($images);?>
// add var ^^^ here
And then make sure you never accidently redeclare that variable later:
else {
...
image_array = []; // no var here
}
To check if an array is either empty or not
A modern way, ES5+:
if (Array.isArray(array) && array.length) {
// array exists and is not empty
}
An old-school way:
typeof array != "undefined"
&& array != null
&& array.length != null
&& array.length > 0
A compact way:
if (typeof array != "undefined" && array != null && array.length != null && array.length > 0) {
// array exists and is not empty
}
A CoffeeScript way:
if array?.length > 0
Why?
Case Undefined
Undefined variable is a variable that you haven't assigned anything to it yet.
let array = new Array(); // "array" !== "array"
typeof array == "undefined"; // => true
Case Null
Generally speaking, null is state of lacking a value. For example a variable is null when you missed or failed to retrieve some data.
array = searchData(); // can't find anything
array == null; // => true
Case Not an Array
Javascript has a dynamic type system. This means we can't guarantee what type of object a variable holds. There is a chance that we're not talking to an instance of Array.
supposedToBeArray = new SomeObject();
typeof supposedToBeArray.length; // => "undefined"
array = new Array();
typeof array.length; // => "number"
Case Empty Array
Now since we tested all other possibilities, we're talking to an instance of Array. In order to make sure it's not empty, we ask about number of elements it's holding, and making sure it has more than zero elements.
firstArray = [];
firstArray.length > 0; // => false
secondArray = [1,2,3];
secondArray.length > 0; // => true
How about (ECMA 5.1):
if(Array.isArray(image_array) && image_array.length){
// array exists and is not empty
}
This is what I use. The first condition covers truthy, which has both null and undefined. Second condition checks for an empty array.
if(arrayName && arrayName.length > 0){
//do something.
}
or thanks to tsemer's comment I added a second version
if(arrayName && arrayName.length)
Then I made a test for the second condition, using Scratchpad in Firefox:
var array1;
var array2 = [];
var array3 = ["one", "two", "three"];
var array4 = null;
console.log(array1);
console.log(array2);
console.log(array3);
console.log(array4);
if (array1 && array1.length) {
console.log("array1! has a value!");
}
if (array2 && array2.length) {
console.log("array2! has a value!");
}
if (array3 && array3.length) {
console.log("array3! has a value!");
}
if (array4 && array4.length) {
console.log("array4! has a value!");
}
which also proves that if(array2 && array2.length) and if(array2 && array2.length > 0) are exactly doing the same
optional chaining
As optional chaining proposal reached stage 4 and is getting wider support, there is a very elegant way to do this
if(image_array?.length){
// image_array is defined and has at least one element
}
You should use:
if (image_array !== undefined && image_array.length > 0)
If you want to test whether the image array variable had been defined you can do it like this
if(typeof image_array === 'undefined') {
// it is not defined yet
} else if (image_array.length > 0) {
// you have a greater than zero length array
}
JavaScript
( typeof(myArray) !== 'undefined' && Array.isArray(myArray) && myArray.length > 0 )
Lodash & Underscore
( _.isArray(myArray) && myArray.length > 0 )
You can use jQuery's isEmptyObject() to check whether the array contains elements or not.
var testArray=[1,2,3,4,5];
var testArray1=[];
console.log(jQuery.isEmptyObject(testArray)); //false
console.log(jQuery.isEmptyObject(testArray1)); //true
Source: https://api.jquery.com/jQuery.isEmptyObject/
Using undescore or lodash:
_.isArray(image_array) && !_.isEmpty(image_array)
A simple way that doesn't result in exceptions if not exist and convert to boolean:
!!array
Example:
if (!!arr) {
// array exists
}
How about this ? checking for length of undefined array may throw exception.
if(image_array){
//array exists
if(image_array.length){
//array has length greater than zero
}
}
The best is to check like:
let someArray: string[] = [];
let hasAny1: boolean = !!someArray && !!someArray.length;
let hasAny2: boolean = !!someArray && someArray.length > 0; //or like this
console.log("And now on empty......", hasAny1, hasAny2);
See full samples list:
I come across this issue quite a lot in Javascript. For me the best way to do it is to put a very broad check before checking for length. I saw some other solutions in this Q&A, but I wanted to be able to check for either null or undefined or any other false value.
if(!array || array.length == 0){
console.log("Array is either empty or does not exist")
}
This will first check for undefined, null, or other false values. If any of those are true, it will complete the boolean as this is an OR. Then the more risky check of array.length, which could error us if array is undefined, can be checked. This will never be reached if array is undefined or null, so the ordering of conditions is very important.
If you do not have a variable declared as array you can create a check:
if(x && x.constructor==Array && x.length){
console.log("is array and filed");
}else{
var x= [];
console.log('x = empty array');
}
This checks if variable x exists and if it is, checks if it is a filled array. else it creates an empty array (or you can do other stuff);
If you are certain there is an array variable created there is a simple check:
var x = [];
if(!x.length){
console.log('empty');
} else {
console.log('full');
}
You can check my fiddle here with shows most possible ways to check array.
The following is my solution wrapped in a function that also throws
errors to manage a couple of problems with object scope and all types
of possible data types passed to the function.
Here's my fiddle used to examine this problem (source)
var jill = [0];
var jack;
//"Uncaught ReferenceError: jack is not defined"
//if (typeof jack === 'undefined' || jack === null) {
//if (jack) {
//if (jack in window) {
//if (window.hasOwnP=roperty('jack')){
//if (jack in window){
function isemptyArray (arraynamed){
//cam also check argument length
if (arguments.length === 0) {
throw "No argument supplied";
}
//console.log(arguments.length, "number of arguments found");
if (typeof arraynamed !== "undefined" && arraynamed !== null) {
//console.log("found arraynamed has a value");
if ((arraynamed instanceof Array) === true){
//console.log("I'm an array");
if (arraynamed.length === 0) {
//console.log ("I'm empty");
return true;
} else {
return false;
}//end length check
} else {
//bad type
throw "Argument is not an array";
} //end type check
} else {
//bad argument
throw "Argument is invalid, check initialization";;
}//end argument check
}
try {
console.log(isemptyArray(jill));
} catch (e) {
console.log ("error caught:",e);
}
the way I found to work (comming from another language) is to make a simple function to test.
create a function that check the size of the array and pass the lenght by parameter.
isEmpty(size){
if(size==0) {
return true;
} else {
return false;
}
}
//then check
if(isEmpty(yourArray.length)==true){
//its empty
} else {
//not empty
}
You should do this
if (!image_array) {
// image_array defined but not assigned automatically coerces to false
} else if (!(0 in image_array)) {
// empty array
// doSomething
}
For me sure some of the high rated answers "work" when I put them into jsfiddle, but when I have a dynamically generated amount of array list a lot of this code in the answers just doesn't work for ME.
This is what IS working for me.
var from = [];
if(typeof from[0] !== undefined) {
//...
}
Notice, NO quotes around undefined and I'm not bothering with the length.
Probably your image_array is not array but some OBJECT with length property (like string) - try
if(image_array instanceof Array && image_array.length)
function test(image_array) {
if(image_array instanceof Array && image_array.length) {
console.log(image_array,'- it is not empty array!')
} else {
console.log(image_array,'- it is empty array or not array at all!')
}
}
test({length:5});
test('undefined');
test([]);
test(["abc"]);
In my case, array_.length always returned 0, even if it had values inside. Probably, because of non-default indexes.
So to check if array is defined we use typeof _array !== 'undefined'
And then to check if it contains any date i just simply compare it to an empty array _array !== []
in ts
isArray(obj: any)
{
return Array.isArray(obj)
}
in html
(photos == undefined || !(isArray(photos) && photos.length > 0) )
When you create your image_array, it's empty, therefore your image_array.length is 0
As stated in the comment below, i edit my answer based on this question's answer) :
var image_array = []
inside the else brackets doesn't change anything to the image_array defined before in the code