Ad

How To Get Next Element In A Sparse Array

- 1 answer

I'm aware that arrays in JavaScript differ from your traditional arrays in the sense that they are just objects under the hood. Because of this, JavaScript allows for sparse arrays to behave in a similar manner to dense arrays when it comes to memory management. When working with a sparse array, is there a way to reach the next element in that array efficiently?

For example, given this array:

var foo = [];
foo[0] = '0';
foo[1] = '1';
foo[2] = '2';
foo[100] = '100';

console.log(foo.length); // => 101

I'm know that there's a way to get all of the elements by using for ... in like so:

for (var n in foo){
    console.log(n);
}
// Output: 
// 0
// 1
// 2
// 100

However, is there an explicit way to simply get from one of these elements to the next?

For example, does there exist some way to achieve similar behavior to this?

var curElement = foo[2]; // => 2 (the contents of foo[2])
var nextElement = curElement.next(); // => 100 (the contents of foo[100])
//                           ^^^^^^
// Not an actual function, but does there exist some way to potentially
// mimic this type of behavior efficiently?
Ad

Answer

You could create your own SparseArray types that has all the Array methods, but maintains a separate list of indices to iterate so that you can skip over holes efficiently.

Here's the start of such a type. It lets you iterate, push, add at specific indices, get/check specific indices.

There's also a .toString() that I added for display.

Not fully tested so there may be bugs. You'd need to add functionality as needed.

function SparseArray(arr) {
  this.data = arr || [];
  this.indices = [];

  for (var i = 0; i < this.data.length; i++) {
    if (this.data.hasOwnProperty(i)) {
      this.indices.push(i);        
    }
  }
}

SparseArray.prototype.forEach = function(cb, thisArg) {
  for (var i = 0; i < this.indices.length; i++) {
    cb.call(thisArg, this.data[this.indices[i]], i, this);
  }
};

SparseArray.prototype.push = function(item) {
  this.indices.push(this.data.push(item) - 1);
};

SparseArray.prototype.addAt = function(idx, item) {
  if (idx >= this.data.length) {
    this.indices.push(idx);
    
  } else if (!(idx in this.data)) {
    for (var i = 0; i < this.indices.length; i++) {
      if (this.indices[i] >= idx) {
        this.indices.splice(i, 0, idx);
        break;
      }
    }
  }
  this.data[idx] = item;
};

SparseArray.prototype.hasIndex = function(idx) {
  return idx in this.data;
};

SparseArray.prototype.getIndex = function(idx) {
  return this.data[idx];
};

SparseArray.prototype.nextFrom = function(idx) {
  for (var i = 0; i < this.indices.length; i++) {
    if (this.indices[i] >= idx) {
      return this.data[this.indices[i]];
    }
  }
};

SparseArray.prototype.toString = function() {
  var res = [];
  this.forEach(function(item) {
    res.push(item);
  });
  return res.join(", ");
};

var foo = [];
foo[0] = '0';
foo[1] = '1';
foo[2] = '2';
foo[100] = '100';

var pre = document.querySelector("pre");

var sa = new SparseArray(foo);

pre.textContent += "Start\n" + sa + "\n\n";

sa.addAt(1000, "1000");

pre.textContent += "Adding 1000\n" + sa + "\n\n";

sa.push("1001");

pre.textContent += "Pushing 1001\n" + sa + "\n\n";

pre.textContent += "Next from 300 is: " + sa.nextFrom(300) + "\n\n";
<pre></pre>

Ad
source: stackoverflow.com
Ad