0

Given two arrays myArray1 and myArray2, which may be null, how can I output a Boolean which tells me if at least one array is non-empty?

Assuming that I have the following variables:

    myArray1 = ["one", "two", "three"]; //-> non-empty array
    myArray2 = null; //-> not an array (in my case this happens from .match() returning no results)

I want an expression, such that myArray1 && myArray2 will be FALSE, but myArray1 || myArray2 will be TRUE.

I did look through other relevant Stack Overflow questions (see an abridged list below), but since I still struggled to figure out the solution, I thought I would post it as a separate question since answers might also benefit others.

The common way of testing for empty arrays is:

    myBooleanOr = (myArray1.length || myArray2.length); //3
    myBooleanAnd = (myArray1.length && myArray2.length); //Error

This works if both variables are arrays, but in this case, the second one will throw up Error: cannot read property length of 'null'. Using the Boolean() function does not solve the problem since the following also throws up the same error:

    myBooleanAnd = (Boolean(myArray1.length) && Boolean(myArray2.length)); //error

A solution for testing empty arrays which was accepted in several Stack Overflow questions is to use typeof myArray !== "undefined", but that still does not solve the problem, because neither of the arrays match "undefined", so myBooleanAnd will still throw up an error:

   var bool = (typeof myArray1 !== "undefined"); //true
   var bool = (typeof myArray2 !== "undefined"); //true
   var myBooleanAnd = ((typeof myArray1 !== "undefined" && myArray1.length) || (typeof myArray2 !== "undefined" && myArray2.length)); //Error: cannot read property length of null

Comparing the arrays against [], which also seems intuitive, also doesn't work, because neither of the arrays match []:

    var bool = (myArray1 !== []); //true
    var bool = (myArray2 !== []); //true

Other relevant posts

A number of other questions on Stack Overflow deal with testing for empty Javascript arrays, including:

And there are also questions about the truth value of empty arrays in Javascript:

UPDATE

I have corrected the following errors posted in the original question (thanks to those who pointed them out). I am listing them here since they might also be helpful to others:

  • ==! changed to !==
  • typeof x === undefined, changed to typeof x === "undefined"
Community
  • 1
  • 1
ATJ
  • 309
  • 2
  • 10
  • There is no `==!` operator in JavaScript. The operator you're looking for is `!==`. – JLRishe Mar 07 '17 at 10:27
  • @JLRishe hm I wondered about that, but I've tested them both and they both work... Is it a question of 'best practice' or just a convention? – ATJ Mar 07 '17 at 10:29
  • 1
    No, it's neither. `==!` is the poorly spaced equivalent of `== !`, i.e. `1 == !'a'` → `1 == false` → `false`. I imagine a lot of your code is going to act differently from your expectation if you're using `==!` everywhere. – JLRishe Mar 07 '17 at 10:32

6 Answers6

2

I would suggest using a helper function to determine if a single array is non-empty, and then use that twice. This is simple and straightforward:

function isNonEmptyArray(arr) {
    return !!(Array.isArray(arr) && arr.length);
}

var myBooleanAnd = isNonEmptyArray(myArray1) && isNonEmptyArray(myArray2);
var myBooleanOr = isNonEmptyArray(myArray1) || isNonEmptyArray(myArray2);
JLRishe
  • 99,490
  • 19
  • 131
  • 169
1

Ok, so, there're a bunch of errors in the code examples, i'll try to to explain them all:

myBooleanOr = (myArray1.length || myArray2.length); //3
myBooleanAnd = (myArray1.length && myArray2.length); //Error

Here, the first line returns the first truthy value it encounters. Since myArray1 has a length > 0, it returns that value and never evaluates the second part of the condition, that's why you're not getting the error. Swap the checks and it will break.
The second line combines the two values to give a result, so it will always give an error when one of the two variables are null.

var bool = (typeof myArray1 === undefined); //false

typeof returns a string, if you compare it to the undefined constant it will always be false, the correct statement is typeof myArray1 === "undefined" as written in most of the posts you linked

var bool = (myArray2 ==! null);

the "strictly not equal" operator is !== and NOT ==!. You're doing a different operation and that's why you get surprising results.

Putting the right spaces in the syntax, this is your code var bool = (myArray2 == !null);

So you boolean-flip the value of null, which is falsy by nature, getting true, and then compare if myArray2 is loosely-equal to true ... since myArray2 is null, and that is falsy as we said, the comparison gives back a false.


That said, for the solution to the question, I'd propose a slightly longer syntax that is more explicit, clear to understand, and you can scale to check how many arrays you like without adding more complexity:

var myArray1 = [1,2,3]
var myArray2 = null

var arrays = [myArray1, myArray2]

var oneNotEmpty = arrays.some( a => typeof a != "undefined" && a != null && a.length > 0)

console.log("At least one array non-empty?", oneNotEmpty)
alebianco
  • 2,475
  • 18
  • 25
0

One solution is the following (with or without Boolean()):

Using Array.isArray() and array.length:

   var myBooleanAnd = Boolean(Array.isArray(myArray2) && myArray2.length) && Boolean(Array.isArray(myArray1) && myArray1.length) ; //false -> OK
   var myBooleanOr = Boolean(Array.isArray(myArray2) && myArray2.length) || Boolean(Array.isArray(myArray1) && myArray1.length) ; //true -> OK

It is also possible to use myArray1 !== null instead of Array.isArray(myArray1), but since the latter is a more specific test, the broader Array.isArray() method seems preferable.

UPDATE

I had previously suggested using the following:

    var myBooleanAnd = Boolean(myArray1 && myArray2); //returns false -> OK
    var myBooleanOr = Boolean(myArray1 || myArray2); //returns true -> OK

but since, as pointed out by @JLRishe, the following expression also returns TRUE, this is not a safe solution, since it will only work in situations where the arrays can never be empty.

   var bool = Boolean([] && []); //returns true -> false positive
ATJ
  • 309
  • 2
  • 10
  • #1 doesn't achieve the stated goal. It doesn't check whether they're arrays or whether they're non-empty. – JLRishe Mar 07 '17 at 10:28
  • @JLRishe The question asks for how to get TRUE if at least one of the arrays contains values. #1 does do that... Am I missing your point? – ATJ Mar 07 '17 at 10:36
  • 1
    It also produces true if they're two empty arrays. That would be a false positive and would mean it does not serve its needed purpose. – JLRishe Mar 07 '17 at 10:38
0

Testing for an array is simple enough:

    var blnIsPopulatedArray = (myArray != null
                            && typeof myArray == "object" 
                            && typeof myArray.length == "number"
                            && myArray.length > 0);

Will return false if 'myArray' isn't an array with at least one item, or true if it is an array with at least one item.

SPlatten
  • 5,334
  • 11
  • 57
  • 128
  • 1
    (typeof null == "object") returns true, so testing against "object" will not exclude myArray2. The test typeof myArray2.length will then return the Error: cannot read property length of null... – ATJ Mar 07 '17 at 10:43
  • @ATJ, which is why I'm also testing for length, length will not be valid if myArray is null. – SPlatten Mar 07 '17 at 10:45
0

You could use isArray to check something is an array or not. Most modern browsers supports it. https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Array/isArray

And then you can combine isArray and array's length to check if something is a valid non empty array or not.

function isOneNotEmpty(arrayOne, arrayTwo){
 
 return (Array.isArray(arrayOne)? arrayOne.length > 0 : false) || (Array.isArray(arrayTwo)? arrayOne.length > 0 : false)
}

console.log(isOneNotEmpty([],null));
console.log(isOneNotEmpty([1,2,3,4],null));
console.log(isOneNotEmpty([3,4,5],[1]));
azs06
  • 3,467
  • 2
  • 21
  • 26
0
function arrayIsEmpty(array) {
 if (!Array.isArray(array)) {
   return false;
 }
 if (array.length == 0) {
   return true;
 }
}
Amit Geek
  • 51
  • 4