I am having a filtering problem..
objArray is the array that needs to be filtered.
selectedNames is an array that contains the values that I want to find in objArray.
I need to fetch all objects that have one or more values from selectedNames in their "names" property (an array) .
The output I am trying to get is :
let result = [{names:["A","B","C","D"]},
{names:["A","B"]},
{names:["A","D"]}
]
Here is a simplified version of my code:
let objArray = [{names:["A","B","C","D"]},
{names:["C","D"]},
{names:["C","D","E"]},
{names:["A","B"]},
{names:["A","D"]}
]
let selectedNames = ["A","B"]
result = this.objArray .filter(obj => {
return this.selectedNames.includes(obj.names)
}
My code seems to work fine if names attribute was a single value and not an array. But I can't figure out how to make it work on an array.
Any help is more than welcome
You could do something like this. Filtering the array based on the names property having 'some' value be included in the selectedNames array.
...
objArray.filter(obj => obj.names.some(name => selectedNames.includes(name)));
[Edit] As #RadicalTurnip pointed out, this is not performant if the selectedNames is too large. I would suggest that you use an object. E.x
...
const selectedNamesMap = selectedNames.reduce((p,c) => ({...p, [c]: true}), {});
objArray.filter(obj => obj.names.some(name => selelectedNamesMap[name]));
Overkill, but if the arrays are really large (millions of elements) then you are better of using regular for loop and not array methods.
This result is not performant scaled up, but I don't know that there is any way to ensure that it will be performant unless you know more information (like the names are already sorted). That being said, you just missed one more piece of logic.
result = this.objArray.filter(obj => {
let toReturn = false;
obj.names.forEach(name => {
if (this.selectedNames.includes(name))
toReturn = true;
};
};
return toReturn;
};
I don't understand, are you required to return a specific way through map?
componentDidMount() {
// read the items db
let categories = [];
items.map(cat => {
if (categories.indexOf(cat.category) === -1) {
categories.push(cat.category);
}
});
console.log(categories);
this.setState({ categories: categories });
}
The purpose of .map is to produce a new array from an old one. The return value from your function specifies what the new value at that spot in the array should be. Since you're not returning anything an array of undefined's will be produced. This is probably a mistake, and therefore that lint rule is warning you about it.
In your case, you don't seem to care about the array that map produces at all, so the fix is to use a more appropriate method, such as .forEach
let categories = [];
items.forEach(cat => {
if (categories.indexOf(cat.category) === -1) {
categories.push(cat.category);
}
});
From the documentation on array-callback-return:
Array has several methods for filtering, mapping, and folding. If we forget to write return statement in a callback of those, it's probably a mistake. If you don't want to use a return or don't need the returned results, consider using .forEach instead.
try to use iterator as for or forEach map don't work the purpose from the map it returns
a new array from want to render it may be undefined or
In your case, you don't seem to care about the array that map produces at all, so the fix is to use a more appropriate method, such as .forEach or for
let categories = [];
const items = [];
for (let cat in items) {
if (categories.indexOf(cat.category) === -1) {
categories.push(cat.category);
}
};
console.log(categories);
enter code here
Yes, it requires you to return something to create the new array.
If you just want to iterate items and push some values to categories array, you can use forEach or for...of.
this.setState({
categories: items.filter(cat => categories.indexOf(cat.category) === -1).map(cat => cat.category)
})
Use filter to remove cat with category already in categories, and use map to create a new categories array.
I have an array of N objects. I would like to write a filter that filters using JSON.stringify based on multiple and dynamic properties.
But dynamic without static properties (like the code above)
Do you have any ideas?
return items.filter(item =>
JSON.stringify(item.prop1 && item.prop2 && ....)
.toLowerCase()
.includes(searchParam)
);
You're gonna have to write a function that transforms your object into a stripped down object with just the properties you want:
function getProperties(obj, propList) {
var newObj = {};
propList.forEach(prop => {
newObj[prop] = obj[prop];
});
return newObj;
}
And then your code will look like this:
var propList = ['id','name','date']; // just for example, put whatever properties you want in here
return items.filter(item =>
JSON.stringify(getProperties(item, propList))
.toLowerCase()
.includes(searchParam)
);
items.filter(item => ["prop1", "prop2"].some(key => item[key].toLowerCase() === searchParam))
Using JSON.stringify to turn the object into a searchable string is a bad idea as the keys are also included in the search and it will be way slower than just traversing the neeeed keys.
I need to remove elements from a json string returned by an AJAX call.
I'm not sure how to loop through the string and remove all elements where the value i NULL.
My json looks like this.
[
{"ID":"27","Agility":"15","Balance":null,"Strength":"37","Physiology":"32"},
{"ID":"30","Agility":"27","Balance":null,"Strength":null,"Physiology":null},
{"ID":"34","Agility":null,"Balance":null,"Strength":null,"Physiology":null},
{"ID":"36","Agility":null,"Balance":null,"Strength":null,"Physiology":null},
{"ID":"40","Agility":null,"Balance":"20","Strength":null,"Physiology":"34"},
{"ID":"42","Agility":null,"Balance":"16","Strength":null,"Physiology":null},
{"ID":"51","Agility":null,"Balance":null,"Strength":"39","Physiology":null}
]
I thought I might do something like this for every key but i would prefer a generic function:
if(json[index].Strength == null){
json.splice(index,1);
}
You can parse json with JSON.parse method and then use filter() method on that array.
const json = '[{"ID":"27","Agility":"15","Balance":null,"Strength":"37","Physiology":"32"},{"ID":"30","Agility":"27","Balance":null,"Strength":null,"Physiology":null},{"ID":"34","Agility":null,"Balance":null,"Strength":null,"Physiology":null},{"ID":"36","Agility":null,"Balance":null,"Strength":null,"Physiology":null},{"ID":"40","Agility":null,"Balance":"20","Strength":null,"Physiology":"34"},{"ID":"42","Agility":null,"Balance":"16","Strength":null,"Physiology":null},{"ID":"51","Agility":null,"Balance":null,"Strength":"39","Physiology":null}]'
const data = JSON.parse(json).filter(o => o.Strength != null)
console.log(data)
If you want to remove elements where some property has value of null you can use some method inside filter.
const json = '[{"ID":"27","Agility":"15","Balance":null,"Strength":"37","Physiology":"32"},{"ID":"30","Agility":"27","Balance":null,"Strength":null,"Physiology":null},{"ID":"34","Agility":null,"Balance":null,"Strength":null,"Physiology":null},{"ID":"36","Agility":null,"Balance":null,"Strength":null,"Physiology":null},{"ID":"40","Agility":null,"Balance":"20","Strength":null,"Physiology":"34"},{"ID":"42","Agility":null,"Balance":"16","Strength":null,"Physiology":null},{"ID":"51","Agility":null,"Balance":null,"Strength":"39","Physiology":null}]'
const data = JSON.parse(json).filter(o => {
return !Object.keys(o).some(k => o[k] == null)
})
console.log(data)
Use filter:
const newJson = json.filter(item => item.Strength !== null)
If you prefer a generic function, Lodash is the best option.
PickBy picks up properties from an object, based on a Predicate.
Here predicate is Identity, which means, pickup non null properties from the object.
var jsonResponse = '[{"ID":"27","Agility":"15","Balance":null,"Strength":"37","Physiology":"32"},{"ID":"30","Agility":"27","Balance":null,"Strength":null,"Physiology":null},{"ID":"34","Agility":null,"Balance":null,"Strength":null,"Physiology":null},{"ID":"36","Agility":null,"Balance":null,"Strength":null,"Physiology":null},{"ID":"40","Agility":null,"Balance":"20","Strength":null,"Physiology":"34"},{"ID":"42","Agility":null,"Balance":"16","Strength":null,"Physiology":null},{"ID":"51","Agility":null,"Balance":null,"Strength":"39","Physiology":null}]';
var responseArr = JSON.parse(jsonResponse);
// Only lines that matter
responseArr = _.map(responseArr, function(obj) {
return _.pickBy(obj, _.identity);
});
console.log("Array of Objects: ", responseArr);
console.log("JSON: ", JSON.stringify(responseArr));
<script src="https://cdn.jsdelivr.net/npm/lodash#4.17.5/lodash.min.js"></script>
Put the above mentioned script tag just before closing tag of your html page.
So just loop through the whole array response using map, and apply PickBy on each object of the array, and you have yourself an array of sparse objects.
Try Array filter() method with ES6 Arrow function.
Demo
var jsonObj = [
{"ID":"27","Agility":"15","Balance":null,"Strength":"37","Physiology":"32"},
{"ID":"30","Agility":"27","Balance":null,"Strength":null,"Physiology":null},
{"ID":"34","Agility":null,"Balance":null,"Strength":null,"Physiology":null},
{"ID":"36","Agility":null,"Balance":null,"Strength":null,"Physiology":null},
{"ID":"40","Agility":null,"Balance":"20","Strength":null,"Physiology":"34"},
{"ID":"42","Agility":null,"Balance":"16","Strength":null,"Physiology":null},
{"ID":"51","Agility":null,"Balance":null,"Strength":"39","Physiology":null}
];
var res = jsonObj.filter(elem => elem.Strength !== null);
console.log(res);
I am using lodash.js in my project, to get a filtered list from a collection "applicationuser". I am using _.filter method in my js file, initially I am getting an array of records to vm.user=[user1,user2,user3,user4] then I want to get filtered list from applicationuser which contains the userid belongs to vm.userid. Usually when I use _.filter method when I have to compare with only one value like this
vm.userlist= _.filter(applicationuser,function(user){
return user.userid= vm.user.userid
});
But at this situation I have to compare with array of users user id as I mentioned above, I wrote for loop in above code as
vm.userlist= _.filter(applicationuser,function(user){
for( var i=0; i<vm.user.length; i++)
{
return user.userid= vm.user[i].userid
}
});
But I am getting unfiltered list (means all records from applicationuser).
This is the way you can achieve the same with lodash way.
vm.userlist= _.filter(applicationuser,function(user){
return _. some(vm.user, function(vuser){
return vuser.id == user.userid;
});
});
The some function checks whether or not any element exists in the array which matches the predicate. Iteration is stopped once predicate returns truthy.
JSFiddle
You are doing = instead of == (assignment instead of comparison).
vm.userlist = _.filter(applicationuser,function(user){
return user.userid == vm.user.userid
});
lodash filter return true/false if you want the item is on your filtered result. You can rewrite your code as follow:
vm.userlist= _.filter(applicationuser,function(user){
return _.filter(vm.user, function(u) {
return u.userid == user.userid;
}).length>0;
});
I can't speak for lodash, but the algorithm you're proposing has O(n^2) runtime, which isn't good.
You can get O(n) runtime if you store userid values in a hashset (all JavaScript Object instances are hashsets) and use the O(1)-runtime in operator:
var allUserIds = {};
for( var i = 0; i < applicationuser.length; i++ ) {
allUserIds[ applicationuser[i].userid ] = i; // storing the value `i` is arbitrary, you could also just store `null` or `true` some other value.
}
vm.userlist = _.filter( applicationuser, u => u.userid in allUserIds );
You don't need lodash for this really - you can use vanilla JavaScript (ECMAScript 5 or above) using Array.prototype.filter:
vm.userlist = applicationuser.filter( u => u.userid in allUserIds );
Update:
After looking at the lodash documentation, lodash has this functionality built-in as the uniq function, which you can use in one-line, without needing to manually create your own hashmap object:
vm.userlist = _.uniq( applicationuser, u => u.userid );