2
    [{ingName: "egg", quantity: "2.0", unit: "pcs"},
    {ingName: "water", quantity: "0.03", unit: "l"},
    {ingName: "salt", quantity: "1.0", unit: "pinch"}],

    [{ingName: "egg", quantity: "2.0", unit: "pcs"},
    {ingName: "water", quantity: "0.03", unit: "l"},
    {ingName: "salt", quantity: "1.0", unit: "pinch"},
    {ingName: "olive oil", quantity: "2.0", unit: "tablespoons"]

I have an array structure as above in my app whenever user clicks make pizza or another recipe it adding recipe informations to new menu state given below.

 <button
       value={item.id}
       onClick={(e) => {setMenu([...menu,{name:item.name,ingredients:item.ingredients}])}}
       className="btn-xs btn-light"
       type="button"
  >
   Make {item.name}
 </button>

After that i need to compare that menu array's ingName and unit fields to calculate total ingredient need for ex. according to above array total is like

total : egg 4pcs , water 0.06 l , salt 2.0 pinch , olive oil 2.0 tablespoons

I tried this :

 menu.map(item => item.ingredients).map((x,index)=> console.log(x[index].ingName)) 

it gets ingName property but after that i stuck.Thanks for help.

Edit :

React Solution : First declared Shyam's solution as function and used useeffect hook for to calculate total ingredients when user clicks button, useeffect updating total array.

     const ingredientFunc = (input1,input2) => {
    const output = input1.reduce(
      (acc, input) => {
        const matchedItem =
          input2.length > 0 &&
          input2.find((item) => item.ingName === input.ingName);
        if (matchedItem) {
          const updatedItem = {
            ingName: input.ingName,
            quantity: Number(input.quantity) + Number(matchedItem.quantity),
            unit: input.unit,
          };
          acc.item.push(updatedItem);
          acc.toFilter.push(matchedItem.ingName);
        } else {
          acc.item.push(input);
        }
        return acc;
      },
      { item: [], toFilter: [] }
    );

    const filteredOutput = input2.filter(
      (item) => !output.toFilter.includes(item.ingName)
    );
    const totalValues = [...output.item, ...filteredOutput];
    setTotal(totalValues);
  }

 React.useEffect(() => {
    if(menu.length === 1 ){
      setTotal(menu[0].ingredients);
    }
      if(menu.length === 2){
        const input1 = menu[0].ingredients;
        const input2 = menu[1].ingredients;
        ingredientFunc(input1,input2)
      }
      if(menu.length >= 3){
        const input1 = total;
        const input2 = menu[indexCount].ingredients;
        ingredientFunc(input1,input2);
        }
      
  },[menu.length,indexCount]);

And modified button

  <button
                      value={item.id}
                      onClick={(e) => {
                        setMenu([
                          ...menu,
                          { name: item.name, ingredients: item.ingredients },
                        ]);
                        setCount(indexCount+1);
                      }}
                      className="btn-xs btn-light"
                      type="button"
                    >

Used indexCount state to locate last added recipe's index.

0

1 Answer 1

1

const input1 =   [{ingName: "egg", quantity: "2.0", unit: "pcs"},
    {ingName: "water", quantity: "0.03", unit: "l"},
    {ingName: "salt", quantity: "1.0", unit: "pinch"}];

const input2 =  [{ingName: "egg", quantity: "2.0", unit: "pcs"},
    {ingName: "water", quantity: "0.03", unit: "l"},
    {ingName: "salt", quantity: "1.0", unit: "pinch"},
    {ingName: "olive oil", quantity: "2.0", unit: "tablespoons"}]; 
     
     
const output = input1.reduce((acc,input) => {
       const matchedItem = input2.length > 0 && input2.find(item => item.ingName === input.ingName);
       if(matchedItem){
       const updatedItem = {
       ingName: input.ingName,
       quantity: Number(input.quantity) + Number(matchedItem.quantity),
       unit: input.unit
    }
       acc.item.push(updatedItem);
       acc.toFilter.push(matchedItem.ingName)
    } else {
      acc.item.push(input)
    }
     
     return acc; 
    }, {item:[] , toFilter: []});


const getFinalReceipes = (input1, input2) => {
  const output = input1.reduce((acc,input) => {
       const matchedItem = input2.length > 0 && input2.find(item => item.ingName === input.ingName);
       if(matchedItem){
       const updatedItem = {
       ingName: input.ingName,
       quantity: Number(input.quantity) + Number(matchedItem.quantity),
       unit: input.unit
    }
       acc.item.push(updatedItem);
       acc.toFilter.push(matchedItem.ingName)
    } else {
      acc.item.push(input)
    }
     
     return acc; 
    }, {item:[] , toFilter: []});
  
  const filteredOutput = input2.filter(item => !output.toFilter.includes(item.ingName));

  const totalValues = [...output.item, ...filteredOutput];
  
  return totalValues;
  
}
     
const mergedReceipes1And2 = getFinalReceipes(input1, input2);

// Pass the merged result as the first argument
const mergedReceipe3 = getFinalReceipes(mergedReceipes1And2, [{ingName: "sugar", quantity: "1.0", unit: "pinch"}])


console.log(mergedReceipe3)

Sign up to request clarification or add additional context in comments.

6 Comments

(Number(input.quantity) + Number(matchedItem.quantity)).toFixed(2) better adding toFixed(2) when adding two number with decimals.
Awesome solution works fine with two arrays but when user add third recipe to list it needs to be merged with totalvalues array im working on it.
In that case i would suggest you to make the above code as a function and change the way how you pass the inputs.
Refactored the code to be a function so that now you can pass 'n' no of receipes . One thing to note here is to pass the merged result to the function .
I got your final refactor but doing this in react states harder than i think thanks for your all effort ill edit my react way solution as soon as possible i marked your comment as answer.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.