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.
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;
};
}
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 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
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!
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;
});
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
});
use filter
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)
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.
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"}]
const y = 'search text';
const a = [{key: "x", "val: "y"}, {key: "d", "val: "z"}]
const data = a.filter(res => {
return(JSON.stringify(res).toLocaleLowerCase()).match(y.toLocaleLowerCase());
});
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 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}});
This question was asked with multiple results in mind, in which case filter
is the way to go, as the other answerers here already pointed out.
However, since this question has become a popular duplicate target, I ought to mention that if you are looking for just a single element satisfying the condition, you don't need filter
and can instead use find
. It works the same way but it simply returns the first matching element or undefined
if no elements match, instead of returning an array of matches:
const data = [
{ id: 1, value: 10 },
{ id: 2, value: 20 },
{ id: 3, value: 30 }
]
console.log(data.filter(o => o.value > 15))
// Output: [{ id: 2, value: 20 }, { id: 3, value: 30 }]
console.log(data.find(o => o.value > 15))
// Output: { id: 2, value: 20 }
console.log(data.filter(o => o.value > 100))
// Output: []
console.log(data.find(o => o.value > 100))
// Output: undefined
// `find` is often useful to find an element by some kind of ID:
console.log(data.find(o => o.id === 3))
// Output: { id: 3, value: 30 }
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);
}
});
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.
const state.contactList = [{
name: 'jane',
email: 'jane@gmail.com'
},{},{},...]
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
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)
You can use forEach
const filterOutputs = [];
json.homes.forEach((home) => {
if (
parseInt(home.price) <= 1000 &&
parseInt(home.sqft) >= 500 &&
parseInt(home.num_of_beds) >= 2 &&
parseInt(home.num_of_baths) >= 2
) {
filterOutputs.push(home);
}
});
console.log(filterOutputs);
I see one case is not covered and maybe someone looks for matching case as I did. Case when someone wants to filter by property value which is string or number using filtering as "where matches" conditional, let's say by city name etc. In other words like Query: return array of ALL homes WHERE city = "Chicago". Solution is simple:
const filterByPropertyValue = (cityName) => {
let filteredItems = homes.filter((item) => item.city === cityName);
console.log("FILTERED HOMES BY CITY:", filteredItems);
}
In case you need to trigger it programmatically or from looping / mapping array in HTML as or by providing 'city' value (you can provide array as well just add it in function to reuse function):
<button
onClick={() => {
filterByPropertyValue("Chicago");
}}
>
Chicago Homes Only
</button>
Let's say JSON has city property added:
'homes': [{
"home_id": "1",
"price": "925",
"sqft": "1100",
"num_of_beds": "2",
"num_of_baths": "2.0",
"city":"Chicago",
}, {
"home_id": "2",
"price": "1425",
"sqft": "1900",
"num_of_beds": "4",
"num_of_baths": "2.5",
"city":"Chicago",
},
// ... (more homes) ...
{
"home_id": "3-will-be-matched",
"price": "925",
"sqft": "1000",
"num_of_beds": "2",
"num_of_baths": "2.5",
"city":"Atlanta",
},
]
Filtering data using an array
const pickupData = [
{
id: 2876635,
pickup_location: "6311cdacf6b493647d86",
address_type: null,
address: "999, Jagarati",``
address_2: "Vihar",
updated_address: false,
old_address: "",
old_address2: "",
city: "Meerut",
state: "Uttar Pradesh",
country: "India",
pin_code: "250001",
email: "938@gmail.com",
is_first_mile_pickup: 0,
phone: "76898",
name: "Aa",
company_id: 2889808,
gstin: null,
vendor_name: null,
status: 2,
phone_verified: 1,
lat: null,
long: null,
warehouse_code: null,
alternate_phone: null,
rto_address_id: 2867270,
lat_long_status: 0,
new: 1,
associated_rto_address: null
},
{
id: 2872407,
pickup_location: "6311cdad490cf6b493647d82",
address_type: null,
address: "Nagar",
address_2: "Delhi",
updated_address: false,
old_address: "",
old_address2: "",
city: "Bijnor",
state: "Uttar Pradesh",
country: "India",
pin_code: "246701",
email: "ima@gmail.com",
is_first_mile_pickup: 0,
phone: "75398",
name: "Amit Sharma",
company_id: 2889808,
gstin: null,
vendor_name: null,
status: 1,
phone_verified: 1,
lat: null,
long: null,
warehouse_code: null,
alternate_phone: null,
rto_address_id: 2867270,
lat_long_status: 0,
new: 1,
associated_rto_address: null
}
];
const shiprocketData = [ { line1: "999, Jagarati", line2: "Vihar", city: "Meerut", state: "Uttar Pradesh", pincode: 250001, country: "India", isCurrent: true, _id: "6311cdad490cf6b3647d86" }, { line1: "999, Jagarati", line2: "Vihar", city: "Meerut", state: "Uttar Pradesh", pincode: 250001, country: "India", isCurrent: true, _id: "6311cdad490cb493647d82" }, { line1: "999, Jagarati", line2: "Vihar", city: "Meerut", state: "Uttar Pradesh", pincode: 250001, country: "India", isCurrent: true, _id: "6311cdad490cf693647d89" } ];
const updatedData = () => {
const data = pickupData.filter(
(item, index) =>
item.pickup_location === shiprocketData.map((item) => item._id)[index]
);
return console.log(data);
};
**
The simplest way to search a specific value in an Array of Object
--------------------------------------------------------------------
filter() -> uses a callback function the return value of which decides what will be returned in the filtered array. If the return value is true, the item is included in the resultant array.
includes() -> searches for something in an array of items using == equality
**
const words = [{id:1,name:"tim"},{id:2,name:"morgon"}]
function searchHandler(enteredString){
const formatedString = enteredString.toLowerCase();
const result = words.filter(data=> data?.name?.includes(formatedString));
console.log(result);
}
精彩评论