How to check if object is empty using lodash _isEmpty? - javascript

i have map function that is returning empty object for the array now if i check array _isEmpty this condition should satisfy but its not getting into if statement. Any idea what is implemented wrong or better approach ?
main.js
const validateResponse = _.map(drugs ,validateValues);
now validateResponse returns [{}] and it should satisfy condition
if (_.isEmpty(validateResponse)) {
throw invalidPriceError;
}

As per the lodash documentation here:
Array-like values such as arguments objects, arrays, buffers, strings, or jQuery-like collections are considered empty if they have a length of 0. Similarly, maps and sets are considered empty if they have a size of 0.
[{}].length happens to be 1. A cabbage-in-a-box, if you will. An array with one empty object. Hence, isEmpty evaluates to false. [].length, on the other hand, equals 0.

You'll have to compact out the internals or check one level deeper:
if (!validateResponse.filter(r => !_.isEmpty(r)).length){
throw invalidPriceError;
}

There might be a handful of other cases you want to cover, like empty array, or an array of two empty objects, etc. Variations on the following should do what you need...
let array = [{}];
// contains any empty object
console.log(_.some(array, _.isEmpty))
// contains only empty objects
console.log(_.every(array, _.isEmpty))
// contains exactly one empty object
console.log(_.every(array, _.isEmpty) && array.length == 1)
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.core.js"></script>

If you just want to check if there is a single array with a single empty object [{}] you can use _.isEqual:
const hasEmpty = arr => _.isEqual(arr, [{}])
console.log(hasEmpty([])) // false
console.log(hasEmpty([{}])) // true
console.log(hasEmpty([{}, {}])) // false
console.log(hasEmpty([{ a: 1 }])) // false
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.js"></script>

Since the array isn't actually empty, but what you're truly checking for is "does the array have exactly one value, and is that single value an empty object?", you could just do this check:
if (validateResponse.length === 1 && _.isEmpty(validateResponse[0])) {
throw invalidPriceError;
}

Related

How can I check if javascript array already contains a specific array

I learn Javascript and read and understand how the includes works to test if a value exists in an array.
My problem comes when I have an Array of items that look like this this:
state = { focused: null, files: [] };:
The image show this here:
When I add a new newFile and it's the same it should not add it ok but the evaluation,
if (newFile && !files.includes(newFile)) {.. always say false so how to test for this do I have to test on individual values inside newFiles?
Array.includes will not do a deep comparison between object, only a shallow one comparing references. This way even objects that have same values they would fail on test because they have different references.
In your case you could compare id, which should be unique for each object. You can use Array.every that checks if all values pass in the test. This way you want to check that every file id doesn't match newFile id:
if (newFile && files.every(({id}) => newFile.id !== id))
Array.includes does reference comparison for Array or Object, so instead you can use Array.filter
if (newFile && newFile.filter(e => { /*Comparison logic */ }).length > 0)

Determine if nested array within object have values

I have an object that looks like this:
steps: {
'36793745-4c52-42d2-91a5-dcdc9de2e8fa': [],
'b23d8770-806f-44a9-aa2e-a21dd68f7977': [],
'33571d58-b833-4a7d-a1a1-ec96366cb74a': [],
'b1499917-7f82-49e5-9708-6237340a9610': []
}
Each array within that object can be an array of strings.
I'd like to check if any of those arrays have an item, if they do, I like to return true.
I do not care about checking any after, as soon as one returns true, I am happy.
I tried something like Object.keys(steps).map(step => steps[step].length > 0) but this returns an array of true or false [false, false, false, false]
I then tried Object.keys(steps).filter(step => steps[step].length > 0) but this returns an array of the item keys that do have a value.
I know at this point I could simply check the length of the result but I was wondering if there is a better way to achieve this.
This object could potentially grow in size considerably, so I was hoping for some sort of early exit as soon as I get a true
You could use the values and a check for the length of the array.
var hasItems = Object.values(steps).some(array => array.length);
Use some.
It can be used to check if at least one element in the array passes a condition or not. Like Array.Filter, it accepts a test function where it loops through the source array’s element.
It returns true if any one of the element passes the test condition. If all the elements fails on the test function, it returns false. it short circuits the loop as soon as one of element passes the test function.
const stepHasProp = Object.values(steps).some(array => array.length)

Merging 2 arrays with different value types

Developing in MEAN stack. Express received and process req array parameters (initially string) and Mongoose returns object array property. I am facing very strange problem. Console.log outputs arrays as follows:
var arr1 = [ '5acde7adf7d2520e3b205970', '5acde7c0f7d2520e3b205971' ];
var arr2 = ["5acde7adf7d2520e3b205970","5acde7c0f7d2520e3b205971"];
first array is a JSON.parsed variable, second the property of MangoDB returned array property.
I need to compare arrays and if they different - perform operation.
Lodash isEqual function is always false.
Lodash union the same as concat and filter, output arrays as follows (log output):
[ 5acde7adf7d2520e3b205970,
5acde7c0f7d2520e3b205971,
'5acde7adf7d2520e3b205970',
'5acde7c0f7d2520e3b205971' ]
If I check types of each array value then the first array values are objects the second are strings...
The only way I can property merge arrays is by preprocessing them like: JSON.parse(JSON.stringify(arr1)). Then all values are strings and merged properly as they shall:
[ '5acde7adf7d2520e3b205970', '5acde7c0f7d2520e3b205971' ]
Anybody faced this problem? Probably have some better ideas how to handle it
The best solution I found, for my problem, is to use map function to even array values. Ex:
arr2.map(String)
If it's always going to be an array of primitives, it should be quite easy to just compare each of their values like so:
const arr1 = [ '5acde7adf7d2520e3b205970', '5acde7c0f7d2520e3b205971' ];
const arr2 = ["5acde7adf7d2520e3b205970","5acde7c0f7d2520e3b205971"];
const isSame = (arr1, arr2) => {
if (arr1.length !== arr2.length) return false;
return arr1.every((arr1elm, i) => arr1elm === arr2[i]);
}
console.log(isSame(arr1, arr2));
The fact that one array may have been defined with double quotes and one with single quotes shouldn't affect anything, since they're already deserialized - it's still an array of strings underneath, not a string itself.

What values do the <empty> elements created by new Array() have?

I'm quite confused by these little guys. After I encountered some funny behavior between them and Array.prototype.filter I fooled around in re.pl trying to understand their true value. But it seems like they switch from <empty> to undefined depending on who's looking (at least in re.pl and node, they're logged as undefined in this environment).
let emptyArr = new Array(5);
//set up two control elements
emptyArr[0] = 0;
emptyArr[4] = undefined;
console.log('\nemptyArr:', emptyArr)
console.log('\npeeking at an empty element:', emptyArr[1])
console.log('\nfilter for undefined elements:', emptyArr.filter(e => e === undefined))
console.log('\nfilter for any element:',
emptyArr.filter(e => {
console.log("ele:", e)
return true
})
) // only two elements are registered here
console.log('\nmappedEmpty:', emptyArr.map(e => e)) //everything is preserved
console.log('\ngenerated array', Array.from(emptyArr))
console.log('\nalways true filter on generated array:', Array.from(emptyArr).filter(e => true)) // empties are now 'true' undefined
What's the story here? Quirky array prototype methods or a secret ultra-false-y value?
What's the story here? Quirky array prototype methods or a secret ultra-false-y value?
Arrays are objects. Elements of the array are simply properties of the underlying object. Accessing a property that doesn't exist returns undefined. Therefore when you access emptyArr[1] you get undefined. Looking at the console of Chrome might help:
As you can see, 0 and 4 exist because you created those entries by assigning to them. 1, 2 and 3 don't exist.
These positions with no value are often referred to as "holes". Your array has holes at positions 1, 2 and 3. An array with holes is also called "sparse array".
Most array methods (.filter, .map, etc) skip over holes. We can easily prove this for some methods:
// Array#map
console.log([,,,42].map(() => 21)); // [,,,21], not [21,21,21,21]
// Array#every
console.log([,,,42].every(x => x === 42)); // true, not false
Of course we could also just look at the language specification, where it says for Array#every for example:
callbackfn is called only for elements of the array which actually exist; it is not called for missing elements of the array.
Array.from on the other hand explicitly looks at the .length property of the value passed to it and it will copy any property/element between 0 and .length. In other words, it does not skip holes.
Look at the difference between the arrays in the Chrome console:
Worth noting maybe that arr.length doesn't care about holes. It will always be the highest set index in the array + 1.
Well actually they do not exist. Imagine arrays being objects, using new Array(5) you will get:
{
length:5
}
So like objects they return undefined for nonset values:
array[3] // undefined
But that doesnt mean theres a property set to undefined. That changes when you use Array.from . You can imagine it doing sth like
for(var i = 0; i < oldarray.lemgth; i++){
newarray[i] = oldarray[i];
}
So after the Array.from call itll look like this:
{
length:5,
0:undefined,
1:undefined,
2:undefined,
3:undefined,
4:undefined
}
They are undefined. It just depends on the engine how it displays them, but trying to access them returns undefined, because that's what they are - elements that have not been defined.
For example the Chrome console will print > (5) [empty × 5] while node prints [ , , , , ] for the same new Array(5). It's just a more visual representation than, say, showing [undefined, undefined, undefined, undefined, undefined].

How to check if array is empty or does not exist? [duplicate]

This question already has answers here:
How to check if an array is empty or exists?
(23 answers)
Closed 2 years ago.
What's the best way to check if an array is empty or does not exist?
Something like this?
if(array.length < 1 || array == undefined){
//empty
}
You want to do the check for undefined first. If you do it the other way round, it will generate an error if the array is undefined.
if (array === undefined || array.length == 0) {
// array does not exist or is empty
}
Update
This answer is getting a fair amount of attention, so I'd like to point out that my original answer, more than anything else, addressed the wrong order of the conditions being evaluated in the question. In this sense, it fails to address several scenarios, such as null values, other types of objects with a length property, etc. It is also not very idiomatic JavaScript.
The foolproof approach
Taking some inspiration from the comments, below is what I currently consider to be the foolproof way to check whether an array is empty or does not exist. It also takes into account that the variable might not refer to an array, but to some other type of object with a length property.
if (!Array.isArray(array) || !array.length) {
// array does not exist, is not an array, or is empty
// ⇒ do not attempt to process array
}
To break it down:
Array.isArray(), unsurprisingly, checks whether its argument is an array. This weeds out values like null, undefined and anything else that is not an array.
Note that this will also eliminate array-like objects, such as the arguments object and DOM NodeList objects. Depending on your situation, this might not be the behavior you're after.
The array.length condition checks whether the variable's length property evaluates to a truthy value. Because the previous condition already established that we are indeed dealing with an array, more strict comparisons like array.length != 0 or array.length !== 0 are not required here.
The pragmatic approach
In a lot of cases, the above might seem like overkill. Maybe you're using a higher order language like TypeScript that does most of the type-checking for you at compile-time, or you really don't care whether the object is actually an array, or just array-like.
In those cases, I tend to go for the following, more idiomatic JavaScript:
if (!array || !array.length) {
// array or array.length are falsy
// ⇒ do not attempt to process array
}
Or, more frequently, its inverse:
if (array && array.length) {
// array and array.length are truthy
// ⇒ probably OK to process array
}
With the introduction of the optional chaining operator (Elvis operator) in ECMAScript 2020, this can be shortened even further:
if (!array?.length) {
// array or array.length are falsy
// ⇒ do not attempt to process array
}
Or the opposite:
if (array?.length) {
// array and array.length are truthy
// ⇒ probably OK to process array
}

Categories