Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does `.forEach` work on dense arrays but not on sparse arrays? [duplicate]

I'm trying to understand the difference between an 'empty' sparse array (e.g. new Array(3)) and an equivalent 'empty' dense array (array with 3 undefined entries).

I can create an array with 3 undefined values these two ways:

var sparse = new Array(3);
// or
var sparse = [,,,];

var dense = Array.apply(null, Array(3)); // See dense array link below

Dense Arrays

If I do console.log for either of these the result is:

[undefined, undefined, undefined]

If I loop over each array to compare it against the other one they will strictly match:

console.log(sparse.length === dense.length);

// true

for (var i = 0; i < dense.length; i++) {
  console.log(i +':'+ (dense[i] === sparse[i]));
}

// '0:true'
// '1:true'
// '2:true'

However, if I use .forEach (or map, reduce, etc) then the callback will never be called on the sparse array but will be called three times on the dense one:

sparse.forEach(function(val,i){
   console.log(i +':'+ val);
});

// Nothing. No-op.

dense.forEach(function(val,i){
   console.log(i +':'+ val);
});

// '0:undefined'
// '1:undefined'
// '2:undefined'

So my questions are:

  1. If they both have the same length, indexes, and values how is one iterable but the other isn't?
  2. What is the reason for the difference?
  3. What is the best way to determine if an array is sparse or dense?
like image 862
pseudosavant Avatar asked Sep 29 '22 13:09

pseudosavant


1 Answers

  1. If they both have the same length, indexes, and values how is one iterable but the other isn't?

These functions are explicitly documented to perform this way. Both arrays are iteratable, but forEach/map/etc explicitly skips indices which are not in the array:

var sparse = new Array(3);
var dense = Array.apply(null, Array(3)); // See dense array link belo

1 in sparse; // false
1 in dense; // true

// Sparse can still be iterated over
sparse[100] = 'a'
sparse.forEach(function (n, i) { console.log(n, i) }); // a 100
  1. What is the reason for the difference?

Presumably an explicit decision was made to omit indices which don't exist

  1. What is the best way to determine if an array is sparse or dense?

You can use the following:

function isSparse(array) {
  for (var i = 0; i < array.length; ++i) {
    if (!i in array)
      return true;
  return false;
}

RE: Your comment

There has got be a reason for why [,,,] doesn't have indexes but [undefined, undefined, undefined] does.

There doesn't have to be a reason, that's just the way they're built. One has keys, the other doesn't.

Look:

Object.keys(Array(3)) // => []
Object.keys(['a','b']) // => ["0", "1"]
like image 172
meagar Avatar answered Oct 03 '22 09:10

meagar