0
\$\begingroup\$

Here is my source code:

// start at zero
var count = 0;
// loop through the items
for(var i = 0; i < hours.length; i++) {
  // 1. check to see if the current item has a key called "description"
  // 2. check to see if the current item's "description" key isn't empty
  // NOTE: white-space only values aren't valid
  if(hours[i].hasOwnProperty("description") && hours[i].description.replace(/\s/g, "").length > 0) {
    // increment the count (by one)
    count += 1;
  }
}
// return the count
return count;

When we remove the comments the code looks like this:

var count = 0;
for(var i = 0; i < hours.length; i++) {
  if(hours[i].hasOwnProperty("description") && hours[i].description.replace(/\s/g, "").length > 0) {
    count += 1;
  }
}
return count;

This appears to be rather expensive (especially with larger arrays). Is there a better (preferably a more concise) way to count the amount of objects in an array that contain a certain key that doesn't have an empty value?

INFO: I can't use jQuery or LoDash/Underscore, all methods must be natively available in the browser and have good browser support (IE8+).

\$\endgroup\$
2
\$\begingroup\$

Using String.replace means that you need to step over every character in every string you are testing. Not only that but it needs to allocate memory to hold the resulting new string.

Its much quicker if you test for a non white space characters. That way it need only test to the first non white space, and it needs no additional memory.

Also Object.hasOwnProperty is slow as it must work its way up the prototype chain to get an answer and should only be used if you think that the object you are testing has a prototype chain containing the property name you are testing.

Last point. This is not part of the code you have presented, but to improve the performance the property hour.description should not contain only white spaces. When you set that property vet it eg hour.description = descriptionString.trim();

Thus If you have unvetted description strings

var i, count = 0;
for (i = 0; i < hours.length; i++) {
    count += hours[i].description && (/\S/).test(hours[i].description) ? 1 : 0;
}
return count;

Or

If the description has been vetted then the following will be the quickest

var i, count = 0;
for (i = 0; i < hours.length; i++) {
    count += hours[i].description ? 1 : 0;
}
return count;
\$\endgroup\$
1
\$\begingroup\$

I'm not a JS performance expert, but you can try this:

var count = 0;
const numHours = hours.length;  // Don't denominate the length on each loop.
for(var i = 0; i < numHours; i++) {
  let description = hours[i].description;  // Don't denominate the description two times.
  // Just search for something that isn't a space character (yes, capital "S").
  if(description && (description.search(/\S/g) !== -1)) {
    count++;  // May be better too.
  }
}
return count;

Also, RegEx are usually expensive, you can try to get rid of them.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.