为了账号安全,请及时绑定邮箱和手机立即绑定

如何按对象过滤对象数组?

如何按对象过滤对象数组?

繁星coding 2022-10-08 17:24:22
我有对象数组:let response = [{"id": 1, "name": "Alise", "price": 400, "category": 4}];我还有一些用于过滤的数组:let names = ["Jessy", "Megan"];let prices = [300, 500];let category = [1,2,4];我需要通过这些数组过滤数组,条件 AND 之间names, prices, category以及OR每个数组中的元素之间的条件:JessyOR Megan.etc我做了这个解决方案:const filterByCategory = (response: IResponse[], filterBy: any[]) => response.filter((e: IResponse) => filterBy.indexOf(e.category) > -1);const filterByPrice =  (response: IResponse[], filterBy: any[]) => response.filter((e: IResponse) => e.price in filterBy);然后我不知道如何更好地拨打电话:单程:filter() {  let filtered = filterByCategory(response, category);  filtered = filterByPrice(filtered, prices);}第二:filter() {   let filtered = [];   if (category && category.length) {      filtered = filterByCategory(response, category);   }   if (prices && prices.length) {       filtered = filterByCategory(filtered, category);   }}第三:let filtered = response.filter((element) => {    return category && category.indexOf(e.category) > -1 &&     prices && prices.indexOf(e.price) > -1 && etc.});首先是简单的修改过滤逻辑,不改变主过滤器第二个和第一个一样,尽管有额外的检查第三是最短的方式,但将来很难修改
查看完整描述

4 回答

?
侃侃尔雅

TA贡献1801条经验 获得超16个赞

像这样的东西是清晰、简洁和可维护的。


const filteredItems = response.filter(e => {

    const validations = {

       containsCategory: category && category.includes(e.category),

       containsPrice: prices && prices.includes(e.price),

       containsName: names && names.includes(e.name),

    };


    return Object.values(validations).every(v => v);

});

您可以在此处使用对象,以便获得命名验证的好处以及能够迭代它们并检查每个validation === true. 如果您将每个验证定义为一个变量,那么您有重复的代码。例如


const filteredItems = response.filter(e => {

   const containsCategory = category && category.includes(e.category);

   const containsPrice = prices && prices.includes(e.price);

   const containsName = names && names.includes(e.name);


   return containsName && containsPrice && containsName;

});

每次要添加验证时,都必须在两个地方(返回和定义)更新名称。


重要的是要注意,虽然有更简洁的方法可以使用您发布的代码实现相同的结果,但这允许您在将来轻松添加更多验证类别 - 而更简洁的解决方案则不能。


例如,您可以轻松地添加字符串过滤器或高级过滤器功能validations:


const validations = {

   matchesSearchString: !searchString || e.name.toLowerCase().startsWith(searchSting.toLowerCase()),

   isAnAncientQueen: isAnAncientQueen(e.name),

   /* -- snip -- */

};


查看完整回答
反对 回复 2022-10-08
?
LEATH

TA贡献1936条经验 获得超7个赞

我想说其他答案更简洁,但是如果您可以利用 TypeScript 的类型系统来制作一个安全且非常通用的解决方案。这种方法是否更可取取决于您在类型安全性和可维护性方面的确切需求。


我的通用方法是定义一个可以应用于任何对象的过滤器类型,然后实现一个知道如何将过滤器应用于任意类型数组的函数。


对于“过滤器”,这将起作用:


type Filter<T> = {

    [P in keyof T]?: (T[P])[]

}

您可以将其理解为“对于Ttype的每个成员X,将有一个可选的同名Filter<T>类型数组。X[]


那么过滤函数就变成了:


function filter<T>(items: T[], filter: Filter<T>): T[]{

    // interim result for easier debugging

    let result =

        items.filter(

            item => {

                // check each member in the filter

                for (let key in filter) {

                    let valueInFilter = filter[key];

                    // if it's empty, then it's OK

                    if (valueInFilter) {

                        // otherwise the value on item MUST be found in the array on filter

                        let valueInItem = item[key];

                        if (valueInFilter.indexOf(valueInItem) == -1) {

                            return false;

                        }

                    }

                }


                // if every check passes, keep the item

                return true;

            }

        );


    return result;

}

把它们放在一起,它看起来像这样:


let responses: IResponse[] = [

    { "id": 1, "name": "Alise", "price": 400, "category": 4 },

    { "id": 2, "name": "Bob", "price": 300, "category": 2 }

];


let someFilter: Filter<IResponse> = {

    id: [1, 2, 4],


    price: [300]

};


console.log(filter(responses, someFilter))

我把它放在TypeScript Playground上,所以你可以看到所有类型检查都有效。


查看完整回答
反对 回复 2022-10-08
?
千巷猫影

TA贡献1829条经验 获得超7个赞

你可以做Array.prototype.filter()满足AND条件Array.prototype.every()OR条件Array.prototype.some()

const response = [{"id": 1, "name": "Alise", "price": 400, "category": 4},{id:2, name:'Megan', price:300, category:2}],

      name = ["Jessy", "Megan"],

      price = [300, 500],

      category = [1,2,4],

      filters = {name,price,category},

      

      

      result = response.filter(o => Object

        .entries(filters)

        .every(([key,values]) => 

          !values.length || values.some(value => o[key] == value)

        )

      )

          

console.log(result)


Array.prototype.includes()基于 - 的方法相比,当(如果)您需要非严格匹配(例如,对某些关键字不区分大小写的部分匹配)时,它可能会更好地缩放



查看完整回答
反对 回复 2022-10-08
?
萧十郎

TA贡献1815条经验 获得超13个赞

您可以获取键和值并检查includes并检查对象的所有过滤器功能。


let

    filter = ([key, values]) => o => !values.length || values.includes(o[key]),

    constraints = {

        id: [], // empty - take all values

        name: ["Jessy", "Megan"],

        price: [300, 500],

        category: [1, 2, 4]

    }

    filters = Object.entries(constraints).map(filter),

    response = [{ id: 1, name: "Alise", price: 400, category: 4 }, { id: 2, name: "Megan", price: 300, category: 4 }],

    result = response.filter(o => filters.every(fn => fn(o)));


console.log(result);

.as-console-wrapper { max-height: 100% !important; top: 0; }


查看完整回答
反对 回复 2022-10-08
  • 4 回答
  • 0 关注
  • 196 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
微信客服

购课补贴
联系客服咨询优惠详情

帮助反馈 APP下载

慕课网APP
您的移动学习伙伴

公众号

扫描二维码
关注慕课网微信公众号