Reputation: 9808
I have a Inventory class that has several methods. 2 Methods return all the lions and wolves they have. One method merges the array from lions and wolves into one array. And finally I have a method that I want to use to filter out certain objects depending on the input.
class Inventory {
getAllLions(): ILion[] {
const lions = [
{ id: 1, name: 'Joffrey', gender: Gender.male, vertrabrates: true, warmBlood: true, hair: 'Golden', runningSpeed: 30, makeSound() { } },
{ id: 2, name: 'Tommen', gender: Gender.male, vertrabrates: true, warmBlood: true, hair: 'Golden', runningSpeed: 30, makeSound() { } },
{ id: 3, name: 'Marcella', gender: Gender.female, vertrabrates: true, warmBlood: true, hair: 'Golden', runningSpeed: 30, makeSound() { } },
];
return lions;
}
getAllWolves(): IWolf[] {
const wolves: IWolf[] = [
{ id: 1, name: 'Jon', gender: Gender.male, vertrabrates: true, warmBlood: true, hair: 'Grey', runningSpeed: 30, makeSound() { } },
{ id: 2, name: 'Robb', gender: Gender.male, vertrabrates: true, warmBlood: true, hair: 'Black', runningSpeed: 30, makeSound() { } },
{ id: 3, name: 'Sansa', gender: Gender.female, vertrabrates: true, warmBlood: true, hair: 'Grey', runningSpeed: 30, makeSound() { } },
{ id: 4, name: 'Arya', gender: Gender.female, vertrabrates: true, warmBlood: true, hair: 'White', runningSpeed: 30, makeSound() { } },
];
return wolves;
}
getAllAnimals(allLions: ILion[], allWolves: IWolf[]): IAnimal[] {
const allAnimals = allLions.concat(allWolves);
return allAnimals
};
static getAnimalBy(name: string, gender: Gender, hair: string, runningSpeed: number, allAnimals): any[] {
let found = false;
let results = [];
for (let animal of allAnimals) {
if (name === animal.name || gender === animal.gender || hair === animal.hair || runningSpeed === animal.runningSpeed) {
found = true;
results.push(animal);
}
}
if (found) { return results } else { alert('No results'); return [] }
}
}
On the getAnimalBy
I have several parameters. These are the parameters the user could filter the animals by. At the moment it only works with one value though. If I do:
const filterdAnimal = Inventory.getAnimalBy(null, Gender.female, null, null, allAnimals);
I get all the results that equal the female gender. But if I do:
const filterdAnimal = Inventory.getAnimalBy(null, Gender.female, 'Golden', null, allAnimals);
It adds the objects that equal Golden
to the results.
What would be a good method to only show the results that would equal the female gender and the golden hair value?
Upvotes: 1
Views: 11014
Reputation: 7641
You can use JS "filter" array function with predicate:
var allAnimals: Array<Animal>;
var found = allAnimals.filter(animal => {
return name === animal.name || gender === animal.gender || hair === animal.hair || runningSpeed === animal.runningSpeed;
});
More over, we can use template object for filtering:
function findByTemplate(allAnimals: Array<Animal>, template: any) {
return allAnimals.filter(animal => {
return Object.keys(template).every(propertyName => animal[propertyName] === template[propertyName]);
});
}
Usage:
var found = findByTemplate(allAnimals, {name: "Aw", gender: "Male"});
var found = findByTemplate(allAnimals, {name: "Aw"});
var found = findByTemplate(allAnimals, {name: "Aw", gender: "Male", hair: "Red", runningSpeed: 50});
Generalized solution:
function findByTemplate(objects: Array<any>, template: any) {
return objects.filter(obj => {
return Object.keys(template).every(propertyName => obj[propertyName] === template[propertyName]);
});
}
We can find by template object in arrays of objects of any types.
Lets we passed array of some objects and the {name: "Aw", gender: "Male"} as a template object.
objects.filter iterates through the array and includes item in filter result if predicate function returns true.
Predicate function:
obj => {
return Object.keys(template).every(propertyName => obj[propertyName] === template[propertyName]);
}
gets keys from passed template
Object.keys(template) for template '{name: "Aw", gender: "Male"}' returns array
["name", "gender"]
So we will check only by passed properties. And we will check whether our condition (another, inner predicate) is true for all items in the '["name", "gender"]' array:
propertyName => obj[propertyName] === template[propertyName]
where propertyName will take "name" and "gender" values.
then propertyName = "name" it tests whether
obj.name === template.name
after that propertyName = "gender" and it tests whether
obj.gender === template.gender
If all tests (name and gender) are passed, we will return true in first predicate and get corresponding object in filter results.
Explanation is larger then code, hope it is clear enough...
Upvotes: 7