最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Filter arrays on multiple values - Stack Overflow

programmeradmin0浏览0评论

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?

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?

Share Improve this question asked May 11, 2016 at 10:10 Peter BoomsmaPeter Boomsma 9,84426 gold badges113 silver badges217 bronze badges 1
  • Use an object as param and, for each (or only predefined) property, check if the animal has this property and if the value matches. – Andreas Commented May 11, 2016 at 10:19
Add a ment  | 

1 Answer 1

Reset to default 7

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

Update 1

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

发布评论

评论列表(0)

  1. 暂无评论