TvdH
TvdH

Reputation: 1218

Make Javascript array elements accessible by additional key

A number of times (especially in MVC scenarios) I had to use an array to store objects, but I also had to access the objects by a property of the stored objects. I may then iterate the array, but I guess (guess because I really know little about Javascript performance) this will be slow already with hundreds of objects and hundreds of iterations. I then build an index like so:

var arr = [];
var index = {};

var o1 = {id: 0, key: "A", data: "X"};
var o2 = {id: 1, key: "B", data: "Y"};

arr.push(o1);
arr.push(o2);
index[o1.key] = o1;
index[o2.key] = o2;

var lookupKey = "B";

// modify object
arr[1].data = "Z";

// get data for key "B" - alerts "Z"
alert(index[lookupKey].data);

(http://jsfiddle.net/timvdh/WT53x/3/)

Of course I have to build and maintain this index... I was wondering if there is a better method?

I guess there is a lib that includes "SortedDictionaries" (the name of such generic collection in .NET) - and I would like to know about is. However, I am also working with specialized arrays (e.g. knockout's observableArray) and I would need a way to index that array, too. Or I need to know that it is simply not worth doing what I am doing with the index.

Upvotes: 1

Views: 280

Answers (2)

paulodiovani
paulodiovani

Reputation: 1305

The best solution I see is, sure, iterate the array.

ECMAScript 6 may introduce the find() method. Until then, ou may create a simple function as bellow (not tested):

function obj_find(arr, key, value) {
    for (var i = 0; i < arr.length; i++) {
        if (arr[i][key] == value) return arr[i];
    }

    return null;
}

I don't think it'll slow down too much your app, since the function returns as soon as it finds the value. But you have thousands of elements to search you may add a cache to speed up the function.

Upvotes: 0

Andy
Andy

Reputation: 63524

Sounds like you're heading in the right direction, but there's a couple of tricks you can employ to get the answer you need without building a separate index.

var arr = [];

arr.push({id: 0, key: "A", data: "X"});
arr.push({id: 1, key: "B", data: "Y"});

arr[1].data = 'Z';

var lookup = 'B';

Now here you can use the filter method* on the array to pull out the object with the correct lookup value.

var result = arr.filter(function(el) {
  return el.key === lookup;
});

Note that results will be an array of all the matches that are found. So, if you only have one element in the array:

console.log(result[0].data) // Z

Let's add another object to the array and rerun the filter:

arr.push({id: 2, key: "B", data: "E"});

And use a loop on the results:

for (var i = 0, l = result.length; i < l; i++) {
  console.log(result[i].data); // Z and E
}

Fiddle

Ultimately you might want to encapsulate this into a function like so:

function findThings(prop, value) {
  return arr.filter(function(el) {
    return el[prop] === value;
  });
}

console.log(findThings('key', 'B')) // an array of two objects that you can loop over

* Note that for older browers you'll need to use a filter polyfill.

Upvotes: 1

Related Questions