[javascript] How to filter object array based on attributes?

I have the following JavaScript array of real estate home objects:

var json = {
    'homes': [{
            "home_id": "1",
            "price": "925",
            "sqft": "1100",
            "num_of_beds": "2",
            "num_of_baths": "2.0",
        }, {
            "home_id": "2",
            "price": "1425",
            "sqft": "1900",
            "num_of_beds": "4",
            "num_of_baths": "2.5",
        },
        // ... (more homes) ...     
    ]
}

var xmlhttp = eval('(' + json + ')');
homes = xmlhttp.homes;

What I would like to do is be able to perform a filter on the object to return a subset of "home" objects.

For example, I want to be able to filter based on: price, sqft, num_of_beds, and num_of_baths.

How can I perform something in JavaScript like the pseudo-code below:

var newArray = homes.filter(
    price <= 1000 & 
    sqft >= 500 & 
    num_of_beds >=2 & 
    num_of_baths >= 2.5 );

Note, the syntax does not have to be exactly like above. This is just an example.

This question is related to javascript

The answer is


You can implement a filter method yourself that meets your needs, here is how:

function myfilter(array, test){
    var passedTest =[];
    for (var i = 0; i < array.length; i++) {
       if(test( array[i]))
          passedTest.push(array[i]);
    }

    return passedTest;
}

var passedHomes = myfilter(homes,function(currentHome){
     return ((currentHome.price <= 1000 )&& (currentHome.sqft >= 500 )&&(currentHome.num_of_beds >=2 )&&(currentHome.num_of_baths >= 2.5));
});

Hope, it helps!


You could do this pretty easily - there are probably many implementations you can choose from, but this is my basic idea (and there is probably some format where you can iterate over an object with jQuery, I just cant think of it right now):

function filter(collection, predicate)
{
    var result = new Array();
    var length = collection.length;

    for(var j = 0; j < length; j++)
    {
        if(predicate(collection[j]) == true)
        {
             result.push(collection[j]);
        }
    }

    return result;
}

And then you could invoke this function like so:

filter(json, function(element)
{
    if(element.price <= 1000 && element.sqft >= 500 && element.num_of_beds > 2 && element.num_of_baths > 2.5)
        return true;

    return false;
});

This way, you can invoke the filter based on whatever predicate you define, or even filter multiple times using smaller filters.


You can use jQuery.grep() since jQuery 1.0:

$.grep(homes, function (h) {
  return h.price <= 1000
    && h.sqft >= 500
    && h.num_of_beds >= 2
    && h.num_of_baths >= 2.5
});

You can try using framework like jLinq - following is a code sample of using jLinq

var results = jLinq.from(data.users)
.startsWith("first", "a")
.orEndsWith("y")
.orderBy("admin", "age")
.select();

For more information you can follow the link http://www.hugoware.net/projects/jlinq


var filterHome = homes.filter(home =>
  return (home.price <= 999 &&
         home.num_of_baths >= 2.5 &&
         home.num_of_beds >=2 &&
         home.sqft >= 998));
console.log(filterHome);

You can use this lambda function. More detail can be found here since we are filtering the data based on you have condition which return true or false and it will collect the data in different array so your actual array will be not modified.

@JGreig Please look into it.


I use my ruleOut function for filtering objects based on specific unwanted property values. I understand that in your example you would like to use conditions instead of values, but my answer is valid for the question title, so I'd like to leave my method here.

function ruleOut(arr, filterObj, applyAllFilters=true) {    
    return arr.filter( row => {            
        for (var field in filterObj) {
            var val = row[field];
            if (val) {                    
                if (applyAllFilters && filterObj[field].indexOf(val) > -1) return false;                
                else if (!applyAllFilters) {                        
                    return filterObj[field].filter(function(filterValue){ 
                        return (val.indexOf(filterValue)>-1);
                    }).length == 0;                 
                }
            }
        }
        return true;
    });
}

Say you have a list of actors like this:

let actors = [
  {userName:"Mary", job:"star", language:"Turkish"},
  {userName:"John", job:"actor", language:"Turkish"},
  {userName:"Takis", job:"star", language:"Greek"},
  {userName:"Joe", job:"star", language:"Turkish"},
  {userName:"Bill", job:"star", language:"Turkish"}
];

and you would like to find all actors that are rated as Holywood stars, their nationality should not be one of 'English', 'Italian', 'Spanish', 'Greek', plus their name would not be one of 'Mary', 'Joe'. Bizzar example, I know! Anyway, with that set of conditions you would create the following object:

let unwantedFieldsFilter= { 
  userName: ['Mary', 'Joe'],    
  job: ['actor'],   
  language: ['English', 'Italian', 'Spanish', 'Greek']  
};

OK, now if you ruleOut(actors, unwantedFieldsFilter) you would only get

[{userName: "Bill", job: "star", language: "Turkish"}]

And Bill is your man, since his name is not one of 'Mary', 'Joe', his nationality is not included in ['English', 'Italian', 'Spanish', 'Greek'] plus he is a Star!

There is one option in my method, that is applyAllFilters and is true by default. If you would try to ruleOut with this param set as false, that would work as an 'OR' filtering instead of 'AND'. Example: ruleOut(actors, {job:["actor"], language:["Italian"]}, false) would get you everyone that is not an actor or Italian:

[{userName: "Mary", job: "star", language: "Turkish"},
{userName: "Takis", job: "star", language: "Greek"},
{userName: "Joe", job: "star", language: "Turkish"},
{userName: "Bill", job: "star", language: "Turkish"}]


advance code for the search for all attributes of the object in arrays

b=[]; 
yourArray.forEach(x => {
      Object.keys(x).forEach(i => {if (x[i].match('5') && !b.filter(y => y === x).length) { b.push(x) }})
    });
console.log(b)

Or you can simply use $.each (which also works for objects, not only arrays) and build a new array like so:

var json = {
    'homes': [{
            "home_id": "1",
            "price": "925",
            "sqft": "1100",
            "num_of_beds": "2",
            "num_of_baths": "2.0",
        }, {
            "home_id": "2",
            "price": "1425",
            "sqft": "1900",
            "num_of_beds": "4",
            "num_of_baths": "2.5",
        },
        // ... (more homes) ...     
        {
            "home_id": "3-will-be-matched",
            "price": "925",
            "sqft": "1000",
            "num_of_beds": "2",
            "num_of_baths": "2.5",
        },
    ]
}

var homes = [];
$.each(json.homes, function(){
    if (this.price <= 1000
        && this.sqft >= 500
        && this.num_of_beds >= 2
        && this.num_of_baths >= 2.5
    ) {
        homes.push(this);
    }
});

here is the working fiddle which works fine in IE8 using jquery MAP function

http://jsfiddle.net/533135/Cj4j7/

json.HOMES = $.map(json.HOMES, function(val, key) {
    if (Number(val.price) <= 1000
            && Number(val.sqft) >= 500
            && Number(val.num_of_beds) >=2
            && Number(val.num_of_baths ) >= 2.5)
        return val;
});

const state.contactList = [{
    name: 'jane',
    email: '[email protected]'
  },{},{},...]

const fileredArray = state.contactsList.filter((contactItem) => {
  const regex = new RegExp(`${action.payload}`, 'gi');
  return contactItem.nameProperty.match(regex) || 
    contactItem.emailProperty.match(regex);
});


// contactList: all the contacts stored in state
// action.payload: whatever typed in search field

use filter

_x000D_
_x000D_
var json = {
    homes: [{
            "home_id": "1",
            "price": "925",
            "sqft": "1100",
            "num_of_beds": "2",
            "num_of_baths": "2.0",
        }, {
            "home_id": "2",
            "price": "1425",
            "sqft": "1900",
            "num_of_beds": "4",
            "num_of_baths": "2.5",
        },
         
    ]
}


let filter = 
  json.homes.filter(d => 
  
    d.price >= 1000 & 
    d.sqft >= 500 & 
    d.num_of_beds >=2 & 
    d.num_of_baths >= 2.5
)

console.log(filter)
_x000D_
_x000D_
_x000D_


I prefer the Underscore framework. It suggests many useful operations with objects. Your task:

var newArray = homes.filter(
    price <= 1000 & 
    sqft >= 500 &
    num_of_beds >=2 & 
    num_of_baths >= 2.5);

can be overwriten like:

var newArray = _.filter (homes, function(home) {
    return home.price<=1000 && sqft>=500 && num_of_beds>=2 && num_of_baths>=2.5;
});

Hope it will be useful for you!


const x = JSON.stringify(data);
const y = 'search text';

const data = x.filter(res => {
        return(JSON.stringify(res).toLocaleLowerCase()).match(x.toLocaleLowerCase());
      });

I'm surprised no one has posted the one-line response:

const filteredHomes = json.homes.filter(x => x.price <= 1000 && x.sqft >= 500 && x.num_of_beds >=2 && x.num_of_baths >= 2.5);

...and just so you can read it easier:

const filteredHomes = json.homes.filter( x => 
  x.price <= 1000 && 
  x.sqft >= 500 && 
  x.num_of_beds >=2 && 
  x.num_of_baths >= 2.5
);

You should check out OGX.List which has built in filtering methods and extends the standard javascript array (and also grouping, sorting and finding). Here's a list of operators it supports for the filters:

'eq' //Equal to
'eqjson' //For deep objects, JSON comparison, equal to
'neq' //Not equal to
'in' //Contains
'nin' //Doesn't contain
'lt' //Lesser than
'lte' //Lesser or equal to
'gt' //Greater than
'gte' //Greater or equal to
'btw' //Between, expects value to be array [_from_, _to_]
'substr' //Substring mode, equal to, expects value to be array [_from_, _to_, _niddle_]
'regex' //Regex match

You can use it this way

  let list = new OGX.List(your_array);
  list.addFilter('price', 'btw', 100, 500);
  list.addFilter('sqft', 'gte', 500);
  let filtered_list = list.filter();

Or even this way

  let list = new OGX.List(your_array);
  let filtered_list = list.get({price:{btw:[100,500]}, sqft:{gte:500}});

Or as a one liner

   let filtered_list = new OGX.List(your_array).get({price:{btw:[100,500]}, sqft:{gte:500}});