34

I have an array like this (with just over 3000 objects instead of the 3 here):

items = [{name:'charlie', age:'16'}, {name:'ben', age:'18'}, {name:'steve', age:'18'}]

What's the best way to return an array with just the objects of people who are 18? So I want:

items = [{name:'ben', age:'18'}, {name:'steve', age:'18'}]

The best I can think of is this (using jQuery):

newArray = []
$.each(items, function(index, item) {
    if(item.age=='18') {
        newArray.push(item)
    }
})

Considering that there's 3000 thousand objects, and also that I'll be doing that comparison up to fifty times in one go, that's a lot of looping. Is there a better way?

Gabriele Petrioli
  • 191,379
  • 34
  • 261
  • 317
Kenny Flannery
  • 373
  • 1
  • 3
  • 5
  • To further clarify, I'm creating this array on initial page load from a database. This same information is needed throughout the experience, so I was thinking accessing it from this array may be quicker than making calls back to the database every time. I need it in the beginning anyhow, so I'm guessing this makes sense. Correct me if there's a better way. – Kenny Flannery Mar 10 '11 at 10:15
  • See following: http://stackoverflow.com/questions/777455/is-there-a-query-language-for-json – Brij Mar 10 '11 at 09:41
  • Kenny : Did you look at @david's solution !!?!? – billy May 03 '12 at 18:00

7 Answers7

59

You can use pure javascript

var wanted = items.filter( function(item){return (item.age==18);} );

And if your browser does not support the 1.6 version of javascript you can find an implementation of the filter method at https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/filter


Update

Speedwise there is a huge varying (had an error in the test) difference from a normal loop (depending on browser).. Have a look at this little test i made at http://jsperf.com/array-filter-vs-loop/3

Gabriele Petrioli
  • 191,379
  • 34
  • 261
  • 317
  • This seems fairly simple, I like it and can use it for a lot more as well. Just poking around some of these other suggestions to see if anything may be better performance-wise, I assume this loops in the background quite a bit, but maybe it won't be an issue. – Kenny Flannery Mar 10 '11 at 10:10
  • @Kenny Flannery: The "disadvantage" is that you make a function call per item. A normal `for` loop is probably faster. – Felix Kling Mar 10 '11 at 10:35
  • Nice test link, using the for loop for now. – Kenny Flannery Mar 11 '11 at 01:08
9

Get matched item and items using find() and filter() method

If you want first matched single item, use find() method which returns single object.

If you want all matched , use filter() method which returns array of objects.

let items = [{name:'charlie', age:'16'}, 
{name:'ben', age:'18'}, 
{name:'steve', age:'18'}]

let all = items.filter(item=> item.age==='18')
console.log(all);

let single = items.find(item=> item.age==='18')
console.log(single);
akhtarvahid
  • 9,445
  • 2
  • 26
  • 29
7

If you're going to do the search often it may be best to keep a version of your data in a form that is quick to access. I've used underscore.js (http://documentcloud.github.com/underscore/) to make it easy for myself, but this code here will create an object that holds your data indexed by the age field.

You end up with something that looks like this:

{
    "16": [
        {
            "name": "charlie",
            "age": "16"
        }
    ],
    "18": [
        {
            "name": "ben",
            "age": "18"
        },
        {
            "name": "steve",
            "age": "18"
        }
    ]
}

The code:

var itemsByAge = _(items).reduce(function(memo, item) {
    memo[item.age] = memo[item.age] || [];
    memo[item.age].push(item);
    return memo;
}, {});

alert(JSON.stringify(itemsByAge["18"]));
david
  • 17,925
  • 4
  • 43
  • 57
4

No matter which method you choose (items.filter or any "query language" for json), a for loop is inevitable.

If performance is a concern, I would recommend you to use pure javascript instead of libraries like jQuery which will add overheads to the whole processing as is evident here.

Thus, your code would look like:

var newArray = [];
for(var i=0;i<items.length;i++) {
    var item = items[i];
    if(item.age == '18') {
        newArray.push(item);
    }
});
Sumit
  • 540
  • 9
  • 20
2

making use of javascript magnificent function eval() which evaluates string as code at runtime, we can define a prototype method for Array type

Array.prototype.where = function (query) {
var newArray = [];
for(var i=0; i<this.length; i++) {
    var item = this[i];
    if(eval( "item" + query )) {
        newArray.push(item);
    }
}
return newArray;
};

and use it with any array, passing the query as string

var newArray= items.where('.age >= 18');
Mohamed Ali
  • 3,717
  • 1
  • 33
  • 39
0

Use the filter method of the array, it calls the provided callbackfunction once for each element in an array.

array.filter(<callbackfucntion>[, <Object to use>])
CloudyMarble
  • 36,908
  • 70
  • 97
  • 130
0

once i had such problem and i solved it like this 1- create an array of array 2- each index create an Index record e.g.

var pAry=[];
var cAry=[{name:'ben', age:'18'}, {name:'steve', age:'18'}]
pAry[17]=cAry;

This way when u require person with age 18, you will get on index 17.