I have an array of ~11,000 JavaScript dictionaries, each representing 1 row in an Excel file.
I want to loop through this array and parse each element into a new datastructure. For example, I might have a function that will count for {"foo": true} or something.
As I have multiple of these functions, my question is would it be better to loop through this array for each function, or have one single loop with functions that parse each element and store it in a global variable?
Ex. I'm currently doing one single loop, and parsing each element into a global variable
const arr = [...]; // array of ~11,000 dictionaries
// example parsing function
let count = 0;
function countFoos(el) {
if (el["foo"] === true) count++;
}
let count2 = 0;
function countBars(el) {
if (el["bar"] === false) count2++;
}
arr.forEach(el => {
countFoos(el);
countBars(el);
});
But would it be better to do it this way?
class Parse {
constructor(arr) {
this.arr = arr;
this.count = 0;
this.count2 = 0;
}
countFoos() {
this.arr.forEach((el) => {
if (el["foo"] === true) this.count++;
});
}
countBars() {
this.arr.forEach((el) => {
if (el["bar"] === false) this.count2++;
});
}
}
const arr = [...]; // array of ~11,000 dictionaries
let x = Parse();
x.countFoos();
x.countBars();
EDIT: I should've clarified early, the examples shown above are just very simplified examples of the production code. Approximately 20 'parsing functions' are being run on for each element, with each of its corresponding global variables being large dictionaries or arrays.
You should generally do just one iteration that calls both functions.
Iterating takes time, so doing two iterations will double the time taken to perform the iterations. How significant this is to the entire application depends on how much work is done in the body of the iteration. If the bodies are very expensive, the iteration time might fall into the noise. But if it's really simple, as in your examples of a simple test and variable increment, the iteration time will probably be significant.
If you are worried about performance, the first method is better as it only involves one iteration over the entire array while the second approach requires two.
If think using classes is more readable, you could simply put write that as one method in the class.
class Parse {
constructor(arr) {
this.arr = arr;
this.count = 0;
this.count2 = 0;
}
count() {
this.arr.forEach((el) => {
countFoos(el), countBars(el);
});
}
countFoos(el){
if(el.foo === true) this.count1++;
}
countBars() {
if(el.bar === false) this.count2++;
}
}
I would approach this by using the Array.prototype.reduce function, which would only require a single pass over the given array. I also would not use a class here as it would not really make sense, but you can if you really want!
function count(arr) {
return arr.reduce(([fooCount, barCount], next) => {
if (next.foo === true) {
fooCount = fooCount + 1
}
if (next.bar === false) {
barCount = barCount + 1
}
return [fooCount, barCount]
}, [0, 0]);
}
const [fooCount, barCount] = count(...);
You can also use generators to accomplish this, which is even better because it doesn't require that you to iterate the entire set of words in the dictionary, but it's a little more unwieldy to use.
This is actually easier to use than other examples that require if statements, because you could quite easily run a battery of functions over each result and add it to the accumulator.
Just remember though that you don't want to optimize before you prove something is a problem. Iterating 22000 objects is obviously more than iterating 11000, but it is still going to be quite fast!
Restricting the number of loops is your best option as it requires less overhead.
Also here is an idea, using the foreach to do the processing with if statements and using a single counter object to hold all of the values so they mean something and can be easily referenced later on.
const arr = [
{"foo" : true,"bar" : false},{"bar" : true,"foo" : false}
];
let counters = {};
function inc(field) {
if (counters[field] == undefined) {
counters[field] = 0;
}
counters[field]++;
}
arr.forEach(el => {
if (el["foo"] === true) {
inc("foo");
}
if (el["bar"] === true) {
inc("bar");
}
});
console.log(counters);
Is there a way, in Javascript (ES2015), to map only part of a array?
E.g.:
let m = someArray.map(function(n){ if(n===0) return n+1; }
That's it, it would return a mapped array that has less elements than the original one.
Is that something that we could accomplish out of the box with some functional programming technique?
Maps changing the number of elements are icky. It's better to filter first, then map:
let arr2 = arr.filter(e => e === 0).map(e => e + 1);
This is easy with array comprehensions, which were introduced by the ECMAScript 6 draft, but will be postponed to ES7:
let m = [for (n of someArray) if (n===0) n+1]
You won't be able to skip unneeded elements with native Array.prototype.map(). But there's always Array.prototype.reduce() to save the day:
let m = someArray.reduce(function(mem, el) {
if (el === 0) {
mem.push(el + 1);
}
return mem;
}, []);
Array iteration methods are (except for deprecated edge cases1) a concise way of expressing what you'd do with a loop (for(i = 0; i < arr.length; i++) { doSomething(arr[i]) }). When the meaning of the method name is no longer representative, you acheive the exact opposite - instead of using a method that describe the operation, you're using one that doesn't and confuse the reader.
More so, not using this group of methods is more performant. This mostly happens because invoking a function is "expensive".
To use the methods, while being concise, see Bartek's answer.
Alternatively, simply use a loop:
let m = [];
for(v of someArray) {
if(v !== 0) {
m.push(v + 1);
}
}
1 When these methods are called, the length of the array is sampled, and any element added beyond this length from within the callback is not visited.
Python has built in functions any() and all(), which are applied on a list (array in JavaScript) as following-
any(): Return True if any element of the iterable is true. If the iterable is empty, return False.
all(): Return True if all elements of the iterable are true (or if the iterable is empty).
We can create our customized functions for above, but please let me know if there any equivalent built-in functions available in JavaScript.
The Python documentation gives you pure-python equivalents for both functions; they are trivial to translate to JavaScript:
function any(iterable) {
for (var index = 0; index < iterable.length; index++) {
if (iterable[index]) return true;
}
return false;
}
and
function all(iterable) {
for (var index = 0; index < iterable.length; index++) {
if (!iterable[index]) return false;
}
return true;
}
Recent browser versions (implementing ECMAScript 5.1, Firefox 1.5+, Chrome, Edge 12+ and IE 9) have native support in the form of Array.some and Array.every; these take a callback that determines if something is 'true' or not:
some_array.some((elem) => !!elem );
some_array.every((elem) => !!elem );
The Mozilla documentation I linked to has polyfills included to recreate these two methods in other JS implementations.
You can use lodash.
lodash.every is equivalent to all
lodash.some is equivalent to any
Build-in function some is equivalent to any I suppose.
const array = [1, 2, 3, 4, 5];
const even = function(element) {
// checks whether an element is even
return element % 2 === 0;
};
console.log(array.some(even));
// expected output: true
You can read more in the docs
I'm doing very frequent searches in arrays of objects and have been using jQuery.inArray(). However, I'm having speed and memory issues and one of the most called methods according to my profiler is jQuery.inArray(). What's the word on the street about its performance? Should I switch to a simple for loop?
My specific function is:
function findPoint(point, list)
{
var l = list.map(function anonMapToId(p) { return p.id });
var found = jQuery.inArray(point.id, l);
return found;
}
Is perhaps list.map() is more to blame?
Well internally inArray makes a simple loop, I would recommend you to check if there is a native Array.prototype.indexOf implementation and use it instead of inArray if available:
function findPoint(point, list) {
var l = list.map(function anonMapToId(p) { return p.id });
var found = ('indexOf' in Array.prototype) ? l.indexOf(point.id)
: jQuery.inArray(point.id, l);
return found;
}
The Array.prototype.indexOf method has been introduced in browsers that implement JavaScript 1.6, and it will be part of the ECMAScript 5 standard.
Native implementations are way faster than non native ones.
What you really want is a Array.prototype.filter.
function findPoint(point, list)
{
return list.filter(function anonFilterToId(p) {
return p.id === point.id;
}).length > 0;
}
Even is the inArray function were slow, you're still creating a full new array for every search. I suppose it would be better to redesign this search, by e.g. creating the id-list before finding the points, and using that one to search into:
I'm doing a join of the array to turn it into a string and avoid the loop section like this :
var strList = ","+array.join(",")+",";
return strList.indexOf(","+search+",") !== -1 ? true : false;
if the array is huge, it can hurt, but for a small list it's much faster than the loop solution
PS I'm adding an ending coma to avoid look a like
I always use lastIndexOf when I want to know if there's a string in my array.
So, its something like this:
var str = 'a';
var arr = ['a','b','c'];
if( arr.lastIndexOf(str) > -1){
alert("String " + str + " was found in array set");
} else {
alert("String " + str + " was not found");
}
If you just want to find a string in array, I do believe this might be the best practice.
What's the fastest way to count the number of keys/properties of an object? Is it possible to do this without iterating over the object? I.e., without doing:
var count = 0;
for (k in myobj) if (myobj.hasOwnProperty(k)) ++count;
(Firefox did provide a magic __count__ property, but this was removed somewhere around version 4.)
To do this in any ES5-compatible environment, such as Node.js, Chrome, Internet Explorer 9+, Firefox 4+, or Safari 5+:
Object.keys(obj).length
Browser compatibility
Object.keys documentation (includes a method you can add to non-ES5 browsers)
You could use this code:
if (!Object.keys) {
Object.keys = function (obj) {
var keys = [],
k;
for (k in obj) {
if (Object.prototype.hasOwnProperty.call(obj, k)) {
keys.push(k);
}
}
return keys;
};
}
Then you can use this in older browsers as well:
var len = Object.keys(obj).length;
If you are using Underscore.js you can use _.size (thanks douwe):
_.size(obj)
Alternatively you can also use _.keys which might be clearer for some:
_.keys(obj).length
I highly recommend Underscore.js. It's a tight library for doing lots of basic things. Whenever possible, they match ECMAScript 5 and defer to the native implementation.
Otherwise I support Avi Flax' answer. I edited it to add a link to the MDC documentation which includes the keys() method you can add to non-ECMAScript 5 browsers.
The standard Object implementation (ES5.1 Object Internal Properties and Methods) does not require an Object to track its number of keys/properties, so there should be no standard way to determine the size of an Object without explicitly or implicitly iterating over its keys.
So here are the most commonly used alternatives:
1. ECMAScript's Object.keys()
Object.keys(obj).length; Works by internally iterating over the keys to compute a temporary array and returns its length.
Pros - Readable and clean syntax. No library or custom code required except a shim if native support is unavailable
Cons - Memory overhead due to the creation of the array.
2. Library-based solutions
Many library-based examples elsewhere in this topic are useful idioms in the context of their library. From a performance viewpoint, however, there is nothing to gain compared to a perfect no-library code since all those library methods actually encapsulate either a for-loop or ES5 Object.keys (native or shimmed).
3. Optimizing a for-loop
The slowest part of such a for-loop is generally the .hasOwnProperty() call, because of the function call overhead. So when I just want the number of entries of a JSON object, I just skip the .hasOwnProperty() call if I know that no code did nor will extend Object.prototype.
Otherwise, your code could be very slightly optimized by making k local (var k) and by using prefix-increment operator (++count) instead of postfix.
var count = 0;
for (var k in myobj) if (myobj.hasOwnProperty(k)) ++count;
Another idea relies on caching the hasOwnProperty method:
var hasOwn = Object.prototype.hasOwnProperty;
var count = 0;
for (var k in myobj) if (hasOwn.call(myobj, k)) ++count;
Whether this is faster or not on a given environment is a question of benchmarking. Very limited performance gain can be expected anyway.
Here are some performance tests for three methods;
https://jsperf.com/get-the-number-of-keys-in-an-object
Object.keys().length
20,735 operations per second
It is very simple and compatible and runs fast but expensive, because it creates a new array of keys, which then gets thrown away.
return Object.keys(objectToRead).length;
Loop through the keys
15,734 operations per second
let size=0;
for(let k in objectToRead) {
size++
}
return size;
It is slightly slower, but nowhere near the memory usage, so it is probably better if you're interested in optimising for mobile or other small machines.
Using Map instead of Object
953,839,338 operations per second
return mapToRead.size;
Basically, Map tracks its own size, so we're just returning a number field. It is far, far faster than any other method. If you have control of the object, convert them to maps instead.
If you are actually running into a performance problem I would suggest wrapping the calls that add/remove properties to/from the object with a function that also increments/decrements an appropriately named (size?) property.
You only need to calculate the initial number of properties once and move on from there. If there isn't an actual performance problem, don't bother. Just wrap that bit of code in a function getNumberOfProperties(object) and be done with it.
As answered in a previous answer: Object.keys(obj).length
But: as we have now a real Map class in ES6, I would suggest to use it instead of using the properties of an object.
const map = new Map();
map.set("key", "value");
map.size; // THE fastest way
this works for both, Arrays and Objects
//count objects/arrays
function count(obj){
return Object.keys(obj).length
}
count objects/arrays with a Loop
function count(obj){
var x=0;
for(k in obj){
x++;
}
return x;
}
count objects/arrays or also the length of a String
function count(obj){
if (typeof (obj) === 'string' || obj instanceof String)
{
return obj.toString().length;
}
return Object.keys(obj).length
}
As stated by Avi Flax,
Object.keys(obj).length
will do the trick for all enumerable properties on your object, but to also include the non-enumerable properties, you can instead use the Object.getOwnPropertyNames. Here's the difference:
var myObject = new Object();
Object.defineProperty(myObject, "nonEnumerableProp", {
enumerable: false
});
Object.defineProperty(myObject, "enumerableProp", {
enumerable: true
});
console.log(Object.getOwnPropertyNames(myObject).length); //outputs 2
console.log(Object.keys(myObject).length); //outputs 1
console.log(myObject.hasOwnProperty("nonEnumerableProp")); //outputs true
console.log(myObject.hasOwnProperty("enumerableProp")); //outputs true
console.log("nonEnumerableProp" in myObject); //outputs true
console.log("enumerableProp" in myObject); //outputs true
As stated here, this has the same browser support as Object.keys.
However, in most cases, you might not want to include the nonenumerables in these type of operations, but it's always good to know the difference ;)
To iterate on Avi Flax' answer, Object.keys(obj).length is correct for an object that doesn’t have functions tied to it.
Example:
obj = {"lol": "what", owo: "pfft"};
Object.keys(obj).length; // should be 2
versus
arr = [];
obj = {"lol": "what", owo: "pfft"};
obj.omg = function(){
_.each(obj, function(a){
arr.push(a);
});
};
Object.keys(obj).length; // should be 3 because it looks like this
/* obj === {"lol": "what", owo: "pfft", omg: function(){_.each(obj, function(a){arr.push(a);});}} */
Steps to avoid this:
do not put functions in an object that you want to count the number of keys in
use a separate object or make a new object specifically for functions (if you want to count how many functions there are in the file using Object.keys(obj).length)
Also, yes, I used the _ or Underscore.js module from Node.js in my example.
Documentation can be found here as well as its source on GitHub and various other information.
And finally a lodash implementation https://lodash.com/docs#size
_.size(obj)
I'm not aware of any way to do this. However, to keep the iterations to a minimum, you could try checking for the existence of __count__ and if it doesn't exist (i.e., not Firefox) then you could iterate over the object and define it for later use, e.g.:
if (myobj.__count__ === undefined) {
myobj.__count__ = ...
}
This way, any browser supporting __count__ would use that, and iterations would only be carried out for those which don't. If the count changes and you can't do this, you could always make it a function:
if (myobj.__count__ === undefined) {
myobj.__count__ = function() { return ... }
myobj.__count__.toString = function() { return this(); }
}
This way, any time you reference myobj.__count__ the function will fire and recalculate.
From Object.defineProperty():
Object.defineProperty(obj, prop, descriptor)
You can either add it to all your objects:
Object.defineProperty(Object.prototype, "length", {
enumerable: false,
get: function() {
return Object.keys(this).length;
}
});
Or a single object:
var myObj = {};
Object.defineProperty(myObj, "length", {
enumerable: false,
get: function() {
return Object.keys(this).length;
}
});
Example:
var myObj = {};
myObj.name = "John Doe";
myObj.email = "leaked#example.com";
myObj.length; // Output: 2
Added that way, it won't be displayed in for..in loops:
for(var i in myObj) {
console.log(i + ": " + myObj[i]);
}
Output:
name: John Doe
email: leaked#example.com
Note: it does not work in browsers before Internet Explorer 9.
For those who have Underscore.js included in their project you can do:
_({a:'', b:''}).size() // => 2
or functional style:
_.size({a:'', b:''}) // => 2
How I've solved this problem is to build my own implementation of a basic list which keeps a record of how many items are stored in the object. It’s very simple. Something like this:
function BasicList()
{
var items = {};
this.count = 0;
this.add = function(index, item)
{
items[index] = item;
this.count++;
}
this.remove = function (index)
{
delete items[index];
this.count--;
}
this.get = function(index)
{
if (undefined === index)
return items;
else
return items[index];
}
}
For those that have Ext JS 4 in their project, you can do:
Ext.Object.getSize(myobj);
The advantage of this is that it'll work on all Ext JS compatible browsers (Internet Explorer 6 - Internet Explorer 8 included). However, I believe the running time is no better than O(n) though, as with other suggested solutions.
You can use:
Object.keys(objectName).length;
and
Object.values(objectName).length;
The OP didn't specify if the object is a nodeList. If it is, then you can just use the length method on it directly. Example:
buttons = document.querySelectorAll('[id=button)) {
console.log('Found ' + buttons.length + ' on the screen');
If jQuery in previous answers does not work, then try
$(Object.Item).length
I try to make it available to all objects like this:
Object.defineProperty(Object.prototype,
"length",
{
get() {
if (!Object.keys) {
Object.keys = function (obj) {
var keys = [],k;
for (k in obj) {
if (Object.prototype.hasOwnProperty.call(obj, k)) {
keys.push(k);
}
}
return keys;
};
}
return Object.keys(this).length;
},});
console.log({"Name":"Joe", "Age":26}.length) // Returns 2