11
\$\begingroup\$

I always did my lookup in JSON collection like that:

var data = [
    {
        "Key": "1111-1111-1111",
        "Email": "[email protected]"
    }
];

function getByKey(key) {
    var found = null;

    for (var i = 0; i < data.length; i++) {
        var element = data[i];

        if (element.Key == key) {
           found = element;
       } 
    }

    return found;
}

But I always wondered if there was a better / more optimal way of doing this.

Any suggestions?

Bonus question: any way of sorting a JSON collection? I found with .sort() and a compare function. Is that the best way?

\$\endgroup\$
2
  • 1
    \$\begingroup\$ Why aren't you using the Array.prototype.filter-method? [{key:"1", name="name"}, ..... ].filter(function(o){ return o.key==="1"}) \$\endgroup\$ May 6, 2013 at 19:33
  • \$\begingroup\$ By the way. You could insert a "break" after you "found" the element. If you (really) have 1 element, that matches. This would speed your code up for average cases. \$\endgroup\$ May 6, 2013 at 20:04

2 Answers 2

8
\$\begingroup\$

Another way you can do it is to have the collection in an object, and use the primary identifier as key. This identifier is usually a unique identifier for that entity, like a user id.

This is way faster than iterating over an array in search for a match. As far as I remember, accessing via a key only takes one operation, O(1) while iterating through an array would depend on the length of the array. Worst case is that your match is at the tip of the array, thus O(n).

var data = {
  "1111-1111-1111" : {
    "Email": "[email protected]"
  }
};

//get by key
var key = "1111-1111-1111";
var oneOneOne = data[key];

oneOneOne.Email //[email protected]

This is only good when you try to get the set by the key. Otherwise, you'd have to resort to other arrangements for other retrievals.

As for sorting though, objects don't guarantee order, though browsers do sort them somehow. As far as I know, iterating through properties of an object in Firefox and Chrome yield different orders in the way they are arranged.

\$\endgroup\$
4
  • 1
    \$\begingroup\$ Which presumes, that the key is unique. \$\endgroup\$ May 6, 2013 at 19:32
  • \$\begingroup\$ @Lilith2k3 Yup. But if you take a look at the OP's code, getByKey only returns one result, thus we could assume that it is unique. \$\endgroup\$
    – Joseph
    May 6, 2013 at 19:54
  • \$\begingroup\$ The question is, whether the TO has neglected that fact by intention. If there were multiple keys, the result would be false, i.e. only the last one. \$\endgroup\$ May 6, 2013 at 20:02
  • \$\begingroup\$ This works of course, assuming getByKey is the only lookup the OP needs. I've been there, as soon as I needed different lookups, this deviates from the optimal. Hence, I prefer mine, with the benefit of (1) not altering how the data arrives (i.e. as an array of objects), which the OP might or might not have control over, (2) looping through it once isn't really so dreadfully expensive, (3) in exchange, you get the ability to create different lookup dictionaries from the same iteration, and (4) sorting with good ol' vanilla javascript .sort(), which is meant to sort arrays, not objects. \$\endgroup\$ May 7, 2013 at 6:46
3
\$\begingroup\$

I tend to generate a lookup dictionary as soon as I have the data. So in any case I only need to iterate the data once.

Comparing with your approach, let's say we need to call getByKey() multiple times, the total cost of iterating the data might actually be higher.

I suppose which approach being more suitable really depends on your own application or design. But I also find myself sometimes generating different lookup dictionaries from the same set of data, and I would still only need to iterate the data once.

As for the .sort() bonus question, I would say that in terms of readability and code maintenance, yes, I would consider it one of the best ways of sorting a json collection.

var data = [
        {
            "Key": "2222-2222-2222",
            "Email": "[email protected]"
        },
        {
            "Key": "1111-1111-1111",
            "Email": "[email protected]"
        }
    ],
    lookup = {};

// generate the lookup table for reuse
data.forEach(function (el, i, arr) {
    lookup[el.Key] = el.Email;
});

// should return '[email protected]'
console.log(lookup['1111-1111-1111']); 

// sort by Key
var keys = data.sort(function (a, b) {
    var c = a.Key,
        d = b.Key;
    return c > d ? 1 :
           d < c ? -1 :
           0;       
});
console.log(keys[0].Key); // should return '1111-1111-1111'

// sort by Email
var emails = data.sort(function (a, b) {
    var c = a.Email,
        d = b.Email;
    return c > d ? 1 :
           d < c ? -1 :
           0;       
});
console.log(emails[0].Key); // should return '2222-2222-2222'
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

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