【问题标题】:Filter an array of objects with a nested array使用嵌套数组过滤对象数组
【发布时间】:2021-06-02 16:34:36
【问题描述】:

我正在尝试对此信息进行过滤,这是来自 API 的一组对象,其中包含数据库中所有产品的信息,在此示例中我只显示一个产品,但 API 请求所有产品。

[
        {
            "Id": 11,
            "Name": "Papas fritas",
            "Description": "Papas",
            "Availability": 1,
            "Price": 1,
            "Stock": 10,
            "Promotion": 0,
            "Discount": 0,
            "Visible": 1,
            "CreationDate": "2021-04-22T18:51:51.000Z",
            "UpdateAt": null,
            "Photo": [
                {
                    "Id": 21,
                    "Photo": "photo.png"
                }
            ],
            "Rating": 4.5,
            "Category": [
                {
                    "Id": 2,
                    "Category": "Moda",
                    "Icon": "Fashion"
                },
                {
                    "Id": 3,
                    "Category": "Fitness",
                    "Icon": "Fitness"
                }
            ],
            "Subcategory": [],
            "Characteristics": [],
  
}

现在我创建了一个具有简短方法的类并过滤了这个数组,但是我在过滤信息时遇到了问题,我不知道如何使用这样的方法按类别过滤信息:

[{Category: 'Art,Fitnness'}]

Promotion 属性也有可能被这样格式化:

[{Promotion: 'true'}]

正如您所见,这个带有过滤器的数组可以有多个属性,并且可以是与类别不同的​​属性,我需要验证这些值,因为数组中的所有值都是字符串,有时 Array.filter 无法进行比较一个字符串 "true" === 1

我为此实现的是这个函数,query是产品的数组,queryvalues是过滤器数组

FilterFuntion(Query, QueryValues)
{
    QueryValues = Object.entries(QueryObj).map((e) => ( { [e[0]]: e[1] } ));
    
    let FilteredArray = Query;

    QueryValues.map((Filter) =>
    {
        var key = Object.keys(Filter)[0];

        FilteredArray = ValidateFilter(key, Filter[key], FilteredArray);
    });

    return FilteredArray;
}

ValidateFilter(Key, Value, array)
{
        return array.filter((El) => 
        {
            if (Value === "true" || Value === "false")
            {
                return Boolean(El[Key]) === Boolean(Value);
            }

            if(Array.isArray((El[Key]))
            {
                 (El[Key]).filter((sub) => 
                 {
                     return String(sub[Key]) === String(Value);
                 });           
            }

            return String(El[Key]) === String(Value);
        });
}

所以我首先验证过滤器的值是 bool 字符串还是 int,然后我返回匹配的值,它对所有正常值都有效,但是当嵌套在另一个数组中的值不起作用时,它返回类别的过滤器数组而不是返回整个产品,当有嵌套数组时,我不知道如何使它工作,当我想过滤多个类别时,我该怎么做?。

[{Category: 'Art,Fitnness'}]

另一件事是,例如,当过滤器的值介于两个数字之间时,例如查看评级属性,我需要过滤并仅返回评级在 5 到 4 之间的产品

[{Promotion: 'true'}, {Category: 'Fitness'}, {Rating: '5,4'}]

【问题讨论】:

    标签: javascript arrays sorting filter


    【解决方案1】:

    使用filter,我们可以从数组中取出每个对象并测试它是否符合条件。

    下面是过滤器对象的剖析:

    filter = {
          Rating: [3, 5],
          Category: [
            ['Fitness','Moda'],
            ['OtherCategory']
          ],
          Promotion: 'false'
        }
    

    Rating 是 'between' 的数组 - 如果您正在寻找一个确切的数字,只需将其输入两次 ([4.5,4.5])。 Category 是一个数组数组,像这样处理or/and

      [
        ['Fitness','Moda'], // product has both categories 'Fitenss' and 'Moda'
        ['OtherCategory'] // OR product has 'OtherCategory'
      ]
    

    const data = [{
        "Id": 11,
        "Name": "Papas fritas",
        "Description": "Papas",
        "Availability": 1,
        "Price": 1,
        "Stock": 10,
        "Promotion": 0,
        "Discount": 0,
        "Visible": 1,
        "CreationDate": "2021-04-22T18:51:51.000Z",
        "UpdateAt": null,
        "Photo": [{
          "Id": 21,
          "Photo": "photo.png"
        }],
        "Rating": 4.5,
        "Category": [{
            "Id": 2,
            "Category": "Moda",
            "Icon": "Fashion"
          },
          {
            "Id": 3,
            "Category": "Fitness",
            "Icon": "Fitness"
          }
        ],
        "Subcategory": [],
        "Characteristics": []
    
      },
      {
        "Id": 13,
        "Name": "Papas fritas2",
        "Description": "Papas2",
        "Availability": 1,
        "Price": 1,
        "Stock": 10,
        "Promotion": 0,
        "Discount": 0,
        "Visible": 1,
        "CreationDate": "2021-04-22T18:51:51.000Z",
        "UpdateAt": null,
        "Photo": [{
          "Id": 21,
          "Photo": "photo.png"
        }],
        "Rating": 3.5,
        "Category": [{
          "Id": 2,
          "Category": "OtherCategory",
          "Icon": "Fashion"
        }],
        "Subcategory": [],
        "Characteristics": []
    
      }
    ]
    
    //[{Promotion: 'true'}, {Category: 'Fitness'}, {Rating: '5,4'}]
    
    
    const filterProductsBy = (criteria, data) => {
      let p = data.filter(obj => {
        let isMatch = true;
        if (criteria.Rating && (obj.Rating < criteria.Rating[0] || obj.Rating > criteria.Rating[1])) isMatch = false;
        if (criteria.Category) {
          let catMatch = false
          // prepare the cat array
          let cats = obj.Category.map(c => c.Category);
          criteria.Category.forEach(set =>
            set.forEach(catAnd => {
              console.log(cats, catAnd, cats.includes(catAnd))
              if (cats.includes(catAnd)) catMatch = true;
            })
          )
          if (!catMatch) isMatch = false;
        }
    
    
    
        if (criteria.Subcategory) {
          let catMatch = false
          // prepare the Subcategory array
          let subcats = obj.Subcategory.map(c => c.Subcategory);
          criteria.Subcategory.forEach(set =>
            set.forEach(catAnd => {
              //console.log(subcats, catAnd, subcats.includes(catAnd))
              if (subcats.includes(catAnd)) catMatch = true;
            })
          )
          if (!catMatch) isMatch = false;
        }
    
    
    
        obj.Promotion = obj.Promotion === 0 ? 'false' : 'true';
        if (criteria.Promotion && obj.Promotion != criteria.Promotion) isMatch = false;
    
    
        return isMatch;
    
      })
    
      return p
    
    }
    
    let filter = {
      Rating: [3, 5],
      Category: [
        ['Fitness']
      ],
      Promotion: 'false'
    }
    
    console.log(filterProductsBy(filter, data))
    
    
    filter = {
      Rating: [3, 5],
      Category: [
        ['Fitness'],
        ['OtherCategory']
      ],
      Promotion: 'false'
    }
    
    console.log(filterProductsBy(filter, data))

    【讨论】:

    • 其实我看错了这个问题。我将更新我的答案,以展示如何按照您询问的方式过滤数据...
    • 这个过滤器是你做的,不要退货
    • @LuisDanielMonsalveRuiz - 现在检查。我创建了一个过滤函数,应该可以解决问题。
    • 实现这一点的代码将受益于 TypeScript,其中您的过滤函数可以接受定义的类型。也就是说,如果在您的项目中使用它是可行的。
    • 兄弟,这真的很棒,谢谢,你能不能像我一样传递关键值而不是标准类别,因为我需要为其他对象做这个白子类别和其他更多操作
    猜你喜欢
    • 1970-01-01
    • 2020-03-11
    • 2020-03-08
    • 1970-01-01
    • 1970-01-01
    • 2022-12-03
    • 1970-01-01
    • 2020-09-17
    • 1970-01-01
    相关资源
    最近更新 更多