通过检查另一个带有对象的嵌套数组来过滤带有对象的嵌套数组

我有一个这样的数组:


const state = {

  products: [

    { name: "Potato", amount: "3"},

    { name: "Butter", amount: "1000" },

    { name: "Salt", amount: "2000" },

    //{name: "Egg", amount: "10"},

    { name: "Tomato",  amount: "5"},

    { name: "Sour Milk", amount: "5"}

  ],


  recipes: [

    {

      name: "Mashed potatoes",

      ingredients: [

        { name: "Potato", amount: "5"},

        { name: "Butter", amount: "30"},

        { name: "Salt", amount: "15"}

      ],

      instructions: "Some Text"

    },

    {

      name: "Tomato Omelette",

      ingredients: [

        { name: "Tomato", amount: "1" },

        { name: "Egg", amount: "1" },

        { name: "Salt", amount: "10" },

        { name: "Butter", amount: "40" }

      ],

      instructions: "Some text"

    }

  ]

};

我想按我可以用我的产品烹饪的食谱过滤我的食谱数组(在这种情况下,我不能做“番茄煎蛋卷”,因为我没有鸡蛋,也不能做“土豆泥”,因为我没有没有足够的土豆)。


到目前为止,我尝试了不同的方法,但我没有想出一个完整的解决方案。


我最接近的解决方案是:


const filterRecipes = (filter, products, recipes) => {


  if(filter === 'available products') {

      //Getting all product names for future tests

      const productsNames = products.map(item => item.name);


      //Here we will filter all our recipes by available products 

      const result = recipes.filter(recipe => {

          //Getting all ingredient names of the current recipe

          const ingredientNames = recipe.ingredients.map(item => item.name);


          //If we have all products for our recipe

          //we will add it to our filtered array

          if (ingredientNames.every((name) => productsNames.includes(name))){

              return true;

          }

      })


      console.log(result);

  }

};

这仅适用于产品名称,但不适用于其数量。当我试图检查它刚刚打破的金额时。


呼如林
浏览 165回答 3
3回答

潇湘沐

我们可以这样做:设置一个productsObjwith reduce 以允许快速查找过滤食谱数组在食谱过滤器函数的每个回调中,并循环每个食谱的成分对于每种成分,检查它是否存在productsObj并且数量大于或等于配方成分中的项目。如果它存在并且数量足够大,请继续检查其余成分如果不是,则返回 false - 即过滤出数组。const state = {&nbsp; products: [&nbsp; &nbsp; { name: "Potato", amount: "5" },&nbsp; &nbsp; { name: "Butter", amount: "1000" },&nbsp; &nbsp; { name: "Salt", amount: "2000" },&nbsp; &nbsp; { name: "Egg", amount: "10" },&nbsp; &nbsp; { name: "Tomato", amount: "5" },&nbsp; &nbsp; { name: "Sour Milk", amount: "5" }&nbsp; ],&nbsp; recipes: [&nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; name: "Mashed potatoes",&nbsp; &nbsp; &nbsp; ingredients: [&nbsp; &nbsp; &nbsp; &nbsp; { name: "Potato", amount: "5" },&nbsp; &nbsp; &nbsp; &nbsp; { name: "Butter", amount: "30" },&nbsp; &nbsp; &nbsp; &nbsp; { name: "Salt", amount: "15" }&nbsp; &nbsp; &nbsp; ],&nbsp; &nbsp; &nbsp; instructions: "Some Text"&nbsp; &nbsp; },&nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; name: "Tomato Omelette",&nbsp; &nbsp; &nbsp; ingredients: [&nbsp; &nbsp; &nbsp; &nbsp; { name: "Tomato", amount: "1" },&nbsp; &nbsp; &nbsp; &nbsp; { name: "Egg", amount: "1" },&nbsp; &nbsp; &nbsp; &nbsp; { name: "Salt", amount: "10" },&nbsp; &nbsp; &nbsp; &nbsp; { name: "Butter", amount: "40" }&nbsp; &nbsp; &nbsp; ],&nbsp; &nbsp; &nbsp; instructions: "Some text"&nbsp; &nbsp; }&nbsp; ]};const filterRecipes = (filter, products, recipes) => {&nbsp; if (filter === "available products") {&nbsp; &nbsp; //Getting all product names in an object for fast look-up&nbsp; &nbsp; const productsObj = products.reduce((aggObj, item) => {&nbsp; &nbsp; &nbsp; aggObj[item.name] = item;&nbsp; &nbsp; &nbsp; return aggObj;&nbsp; &nbsp; }, {});&nbsp; &nbsp; //console.log("o", productsObj);&nbsp; &nbsp; //Here we will filter all our recipes by available products&nbsp; &nbsp; const result = recipes.filter((recipe) => {&nbsp; &nbsp; &nbsp; let valid = true; //true until proven false&nbsp; &nbsp; &nbsp; //Loop over ingredients of each recipe&nbsp; &nbsp; &nbsp; for (let i = 0; i < recipe.ingredients.length; i++) {&nbsp; &nbsp; &nbsp; &nbsp; const item = recipe.ingredients[i];&nbsp; &nbsp; &nbsp; &nbsp; const lookup = productsObj[item.name] || false;&nbsp; &nbsp; &nbsp; &nbsp; const quantityEnough = lookup&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ? parseInt(lookup.amount) >= parseInt(item.amount)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; : false;&nbsp; &nbsp; &nbsp; &nbsp; if (!quantityEnough) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; valid = false;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; break;&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; return valid;&nbsp; &nbsp; });&nbsp; &nbsp; console.log(result);&nbsp; }};filterRecipes("available products", state.products, state.recipes);.as-console-wrapper { max-height: 100% !important; top: 0; }例如,如果您将产品数量更改为:const state = {&nbsp; products: [&nbsp; &nbsp; { name: "Potato", amount: "4" },&nbsp; &nbsp; { name: "Butter", amount: "1000" },&nbsp; &nbsp; { name: "Salt", amount: "2" },&nbsp; &nbsp; { name: "Egg", amount: "10" },&nbsp; &nbsp; { name: "Tomato", amount: "5" },&nbsp; &nbsp; { name: "Sour Milk", amount: "5" }&nbsp; ],你没有得到任何结果,因为盐和土豆的数量对于任何一种食谱都不够大。

跃然一笑

您可以使用对象以更快地访问,并使用amount数字以获得更好的可比性{&nbsp; &nbsp; Potato: 5,&nbsp; &nbsp; Butter: 1000,&nbsp; &nbsp; Salt: 2000,&nbsp; &nbsp; Tomato: 5,&nbsp; &nbsp; "Sour Milk": 5}并且只循环产品和收据一次。这种方法使用解构赋值,其中属性从对象中取出。它使用对象的值并检查所有成分的可用量。const&nbsp; &nbsp; filter = ({ products, recipes }) => {&nbsp; &nbsp; &nbsp; &nbsp; const avalilable = products.reduce((r, { name, amount }) => (r[name] = +amount, r), {});console.log(avalilable )&nbsp; &nbsp; &nbsp; &nbsp; return recipes.filter(({ ingredients }) =>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ingredients.every(({ name, amount }) => avalilable[name] >= +amount));&nbsp; &nbsp; },&nbsp; &nbsp; state = { products: [{ name: "Potato", amount: "5" }, { name: "Butter", amount: "1000" }, { name: "Salt", amount: "2000" }, { name: "Tomato", amount: "5" }, { name: "Sour Milk", amount: "5" }], recipes: [{ name: "Mashed potatoes", ingredients: [{ name: "Potato", amount: "5" }, { name: "Butter", amount: "30" }, { name: "Salt", amount: "15" }], instructions: "Some Text" }, { name: "Tomato Omelette", ingredients: [{ name: "Tomato", amount: "1" }, { name: "Egg", amount: "1" }, { name: "Salt", amount: "10" }, { name: "Butter", amount: "40" }], instructions: "Some text" }] },&nbsp; &nbsp; recipes = filter(state);console.log(recipes);

慕桂英4014372

你可以试试这个解决方案。在这里,我添加了一种解决方案,例如,您有“盐”20单位,而第一个食谱采用它们的单位进行烹饪。15现在假设,第二个配方需要10单位的盐,但你5的商店里还有单位。在这种情况下,您不能采用第二种烹饪方法。const state = {&nbsp; products: [&nbsp; &nbsp; { name: "Potato", amount: "5"},&nbsp; &nbsp; { name: "Butter", amount: "1000" },&nbsp; &nbsp; { name: "Salt", amount: "20" },&nbsp; &nbsp; { name: "Egg", amount: "1"},&nbsp; &nbsp; { name: "Tomato",&nbsp; amount: "5"},&nbsp; &nbsp; { name: "Sour Milk", amount: "5"}&nbsp; ],&nbsp; recipes: [&nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; name: "Mashed potatoes",&nbsp; &nbsp; &nbsp; ingredients: [&nbsp; &nbsp; &nbsp; &nbsp; { name: "Potato", amount: "5"},&nbsp; &nbsp; &nbsp; &nbsp; { name: "Butter", amount: "30"},&nbsp; &nbsp; &nbsp; &nbsp; { name: "Salt", amount: "15"}&nbsp; &nbsp; &nbsp; ],&nbsp; &nbsp; &nbsp; instructions: "Some Text"&nbsp; &nbsp; },&nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; name: "Tomato Omelette",&nbsp; &nbsp; &nbsp; ingredients: [&nbsp; &nbsp; &nbsp; &nbsp; { name: "Tomato", amount: "1" },&nbsp; &nbsp; &nbsp; &nbsp; { name: "Egg", amount: "1" },&nbsp; &nbsp; &nbsp; &nbsp; { name: "Salt", amount: "10" },&nbsp; &nbsp; &nbsp; &nbsp; { name: "Butter", amount: "40" }&nbsp; &nbsp; &nbsp; ],&nbsp; &nbsp; &nbsp; instructions: "Some text"&nbsp; &nbsp; }&nbsp; ]};const filterRecipes = (filter, products, recipes) => {&nbsp; &nbsp; if (filter === 'available products') {&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; /**&nbsp; &nbsp; &nbsp; &nbsp; * Restructure the products from array to object.&nbsp; &nbsp; &nbsp; &nbsp; * like {Potato: "20", "Salt": "200"}&nbsp; &nbsp; &nbsp; &nbsp; */&nbsp; &nbsp; &nbsp; &nbsp; const store = products.reduce((a, {name, amount}) => {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return {...a, [name]: amount};&nbsp; &nbsp; &nbsp; &nbsp; }, {});&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; const canCook = recipes.filter(recipe => {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; /**&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; * Convert ingredient from array to object like products&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; *&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; */&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; const ingredients = recipe.ingredients.reduce((a, {name, amount}) => {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return {...a, [name]: amount};&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }, {});&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; /**&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; * Check if every ingredients are available at the store&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; */&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; const allow = Object.entries(ingredients).every(([name, amount]) => {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return (store[name] !== undefined && (+store[name]) >= (+amount));&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; });&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; /**&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; * This is for reducing the amount of ingredient from the store&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; * if the recipe is taken for cooking.&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; * You can omit it if you don't need to measure this factor.&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; */&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if (allow) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Object.entries(ingredients).forEach(([name, amount]) => {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; store[name] -= amount;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; });&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return allow;&nbsp; &nbsp; &nbsp; &nbsp; });&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; console.log(canCook);&nbsp; &nbsp; }}filterRecipes("available products", state.products, state.recipes);.as-console-wrapper {min-height: 100% !important; top: 0;}
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

JavaScript