【问题标题】:Javascript - Multiple nested filter expressionsJavascript - 多个嵌套过滤器表达式
【发布时间】:2020-05-09 00:14:51
【问题描述】:

在来自 API 的 JavaScript 中有这个 JSON 对象:

[
  {
    "id": 1,
    "label": "Breakfast",
    "subCategories": [
      {
        "id": 100,
        "label": "Cereals, Muesli",
        "items": [
          {
            "productId": "4fdddf1d-8d31-411d-a908-5edd68a775b7",
            "label": "Bircher Muesli"
          },
          {
            "productId": "000673e7-47ec-4dce-a940-ad4aacbd7d73",
            "label": "Individual Cereals"
          },
          {
            "productId": "0f739661-5531-4734-9dfd-e145b60667cc",
            "label": "Organic Porridge Oats"
          }
        ]
      },
      {
        "id": 101,
        "label": "Eggs, Omelettes",
        "items": [
          {
            "productId": "6d608133-ab44-4f9d-ab8e-fc6a3f955397",
            "label": "Crushed Avocado with Soughdough Toast"
          },
          {
            "productId": "fcfe91ab-e9b1-4dc0-8c57-ffb9646e0658",
            "label": "Crushed Avocado with Crispy Bacon"
          },
          {
            "productId": "2a80e48b-76f6-4bda-abf3-ec8dc7bf1419",
            "label": "Crushed Avocado with Smoked Salmon"
          },
          {
            "productId": "ae35e949-abf3-4795-a5df-9af4250c2185",
            "label": "Egg White Omelette"
          }
        ]
      }
      ]
  },
  {
    "id": 2,
    "label": "Light Lunch",
    "subCategories": [
      {
        "id": 103,
        "label": "Condiments",
        "items": [
          {
            "productId": "25503a9b-b553-4b56-a152-49e4121cf4ae",
            "label": "Butter"
          },
          {
            "productId": "c1dd9761-f170-4e6a-a7d7-5519a4213874",
            "label": "Jam"
          }
        ]
      },
      {
        "id": 104,
        "label": "Yoghurts",
        "items": [
          {
            "productId": "938fed24-6d4c-e0cd-8303-0fcd42c87be4",
            "label": "Fruit Yoghurt",
          },
          {
            "productId": "62137176-0966-4424-9093-51bd7871d31b",
            "label": "Greek Yoghurt",
          },
          {
            "productId": "307e59c4-b103-43d4-988c-75ee539d5d75",
            "label": "Granola Parfait: Layers of Berries, Fruit Granola, Yoghurt & Honey",
          }
        ]
      }
    ]
  }
]

我需要使用针对 items.label 属性的搜索查询(例如:希腊语)过滤上面的这个数组,并让它返回过滤后的结果,如下所示:

[
  {
    "id": 2,
    "label": "Light Lunch",
    "subCategories": [
      {
        "id": 104,
        "label": "Yoghurts",
        "items": [
          {
            "productId": "62137176-0966-4424-9093-51bd7871d31b",
            "label": "Greek Yoghurt",
          }
        ]
      }
    ]
  }
]

我已经尝试了各种使用 filter() 和嵌套 some() 的实现,如 StackOverflow 上所见,但没有返回所需的结果。目前这可行,但只有顶级类别被过滤,嵌套子类别仅在项目匹配时才存在。

var searchQuery="Greek";
var data=[]; //JSON omitted for brevity.
var result = data.filter(a=>{
    return a.subCategories.some(b=> {
        return b.items.some(c=> new RegExp(searchQuery,"i").test(c.label));
    });
});

任何帮助将不胜感激。

【问题讨论】:

  • 你能解释一下“只有顶级类别被过滤,嵌套子类别只有在项目匹配时才存在”是什么意思?结果不正确的例子是什么?

标签: javascript arrays


【解决方案1】:

您可以为此使用Array.reduce,首先迭代每个类别,然后是每个子类别,如果其中一个项目包含搜索查询,则仅将子类别添加到输出中,然后仅将类别添加到如果子类别之一包含搜索查询,则输出:

const data = [{
    "id": 1,
    "label": "Breakfast",
    "subCategories": [{
        "id": 100,
        "label": "Cereals, Muesli",
        "items": [{
            "productId": "4fdddf1d-8d31-411d-a908-5edd68a775b7",
            "label": "Bircher Muesli"
          },
          {
            "productId": "000673e7-47ec-4dce-a940-ad4aacbd7d73",
            "label": "Individual Cereals"
          },
          {
            "productId": "0f739661-5531-4734-9dfd-e145b60667cc",
            "label": "Organic Porridge Oats"
          }
        ]
      },
      {
        "id": 101,
        "label": "Eggs, Omelettes",
        "items": [{
            "productId": "6d608133-ab44-4f9d-ab8e-fc6a3f955397",
            "label": "Crushed Avocado with Soughdough Toast"
          },
          {
            "productId": "fcfe91ab-e9b1-4dc0-8c57-ffb9646e0658",
            "label": "Crushed Avocado with Crispy Bacon"
          },
          {
            "productId": "2a80e48b-76f6-4bda-abf3-ec8dc7bf1419",
            "label": "Crushed Avocado with Smoked Salmon"
          },
          {
            "productId": "ae35e949-abf3-4795-a5df-9af4250c2185",
            "label": "Egg White Omelette"
          }
        ]
      }
    ]
  },
  {
    "id": 2,
    "label": "Light Lunch",
    "subCategories": [{
        "id": 103,
        "label": "Condiments",
        "items": [{
            "productId": "25503a9b-b553-4b56-a152-49e4121cf4ae",
            "label": "Butter"
          },
          {
            "productId": "c1dd9761-f170-4e6a-a7d7-5519a4213874",
            "label": "Jam"
          }
        ]
      },
      {
        "id": 104,
        "label": "Yoghurts",
        "items": [{
            "productId": "938fed24-6d4c-e0cd-8303-0fcd42c87be4",
            "label": "Fruit Yoghurt",
          },
          {
            "productId": "62137176-0966-4424-9093-51bd7871d31b",
            "label": "Greek Yoghurt",
          },
          {
            "productId": "307e59c4-b103-43d4-988c-75ee539d5d75",
            "label": "Granola Parfait: Layers of Berries, Fruit Granola, Yoghurt & Honey",
          }
        ]
      }
    ]
  }
];

const searchQuery = "Greek";
const regex = new RegExp(searchQuery, "i");
const result = data.reduce((cats, cat) => {
  cat.subCategories = cat.subCategories.reduce((subs, sub) => {
    sub.items = sub.items.filter(item => regex.test(item.label));
    if (sub.items.length) subs.push(sub);
    return subs;
  }, []);
  if (cat.subCategories.length) cats.push(cat);
  return cats;
}, []);
console.log(result);

【讨论】:

  • 最佳解决方案,效果很好。没有考虑使用 reduce 方法。谢谢!
  • @FraserM 不用担心 - 我很高兴能帮上忙。
【解决方案2】:

这里我有一个返回您请求的输出的工作示例:

function finder(data, query) {
  for(let i in data) {
    // return the item if the label contains the search query
    if(new RegExp(query,"i").test(data[i].label)) return data[i]

    // go deeper in subCategories if exist
    if(data[i].subCategories) {
      let sub = finder(data[i].subCategories, query)
      if(sub) {
        data[i].subCategories = [sub]
        return data[i]
      }

    // go deeper in items if exist
    } else if(data[i].items){
      let item = finder(data[i].items, query)
      if(item) {
        data[i].items = [item]
        return data[i]
      }
    }
  }
  // didn't find the search query in this branch
  return false
}

console.log(finder(data, 'Greek'))

data 你的输入数据

【讨论】:

  • 我认为您不应该为此使用正则表达式。例如,如果用户键入点号,他们可能不希望它匹配任何字符。请改用a.toLowerCase() === b.toLowerCase()
猜你喜欢
  • 1970-01-01
  • 2022-08-19
  • 2020-08-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-08-25
  • 2019-05-23
相关资源
最近更新 更多