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.

Answers:

Answer

You can use the Array.prototype.filter method:

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

Live Example:

var obj = {
    '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) ...     
    ]
};
// (Note that because `price` and such are given as strings in your object,
// the below relies on the fact that <= and >= with a string and number
// will coerce the string to a number before comparing.)
var newArray = obj.homes.filter(function (el) {
  return el.price <= 1000 &&
         el.sqft >= 500 &&
         el.num_of_beds >= 2 &&
         el.num_of_baths >= 1.5; // Changed this so a home would match
});
console.log(newArray);

This method is part of the new ECMAScript 5th Edition standard, and can be found on almost all modern browsers.

For IE, you can include the following method for compatibility:

if (!Array.prototype.filter) {
  Array.prototype.filter = function(fun /*, thisp*/) {
    var len = this.length >>> 0;
    if (typeof fun != "function")
      throw new TypeError();

    var res = [];
    var thisp = arguments[1];
    for (var i = 0; i < len; i++) {
      if (i in this) {
        var val = this[i];
        if (fun.call(thisp, val, i, this))
          res.push(val);
      }
    }
    return res;
  };
}
Answer

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

Answer

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!

Answer

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;
});
Answer

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
);
Answer

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
});
Answer

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.

Answer

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!

Answer

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}});
Answer

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);
    }
});
Answer

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"}]

Answer
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.

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

const data = x.filter(res => {
        return(JSON.stringify(res).toLocaleLowerCase()).match(x.toLocaleLowerCase());
      });
Answer
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
Answer

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)

Tags

Recent Questions

Top Questions

Home Tags Terms of Service Privacy Policy DMCA Contact Us Javascript

©2020 All rights reserved.