1

I need a little help to improve a function where I'm populating an array with 4 random different non-repeating recipes objects using the id of the recipes, but I need to add an additional condition where the recipes should be 1 breakfast, 1 lunch, 1 snack and 1 dinner, for example:

example of JSON with recipes

[
  {
    recipeId: 1,
    recipeTypeId: 1, // breakFast
    "description": "someRecipe",
    "img": "someImgBase64",
  },
  {
    recipeId: 2,
    recipeTypeId: 2, // lunch
    "description": "someRecipe",
    "img": "someImgBase64",
  },
  {
    recipeId: 3,
    recipeTypeId: 3, // snack
    "description": "someRecipe",
    "img": "someImgBase64",
  },
  {
    recipeId: 4,
    recipeTypeId: 4, // dinner
    "description": "someRecipe",
    "img": "someImgBase64",
  },
  {
    recipeId: 5,
    recipeTypeId: 1, // breakfast
    "description": "someRecipe",
    "img": "someImgBase64",
  }
]

this is my function:

randomRecipes() {
  // previously saved recipes from api
  localStorage.getItem('recipesList');
  // random generator
  const randomIndex = new Set();
  const recommendedRandomRecipes: [] = [];
  while (randomIndex.size < 4) {
    randomIndex.add(Math.floor(Math.random() * recipes.length));
  }
  randomIndex.forEach(i => recommendedRandomRecipes.push(recipes[Number(i)]));
  localStorage.addItem('recommendedRecipes', recommendedRandomRecipes);
  this.recipes = recommendedRandomRecipes;
}

the result I want:

recommendedRandomRecipes [1,2,3,4] or [2,3,4,5]

what I don't want

recommendedRandomRecipes [1,2,3,5] // 2 breakfast in the array
Heretic Monkey
  • 11,687
  • 7
  • 53
  • 122
Jordan Quiroz
  • 95
  • 2
  • 10

2 Answers2

1

There are probably many different ways to do this, but here's the strategy I can think of. Basically, you want to generate a list of recipes that contain only one randomly chosen reipce per recipeTypeId. Here are some steps that we can go through:

  1. To accommodate arbitrary number of recipeTypeId, we first iterate through the array and collect all unique values. This can be done by using new Set() and adding them to it
  2. Then, we iterate through this unique set of recipe types. For each set, we generate a filtered array (from the original recipes list), which contains all recipes for a given recipe type. We then pick a random item from there.
  3. Collect all these items and only return their recipeId
  4. Optionally, sort them in increasing order (as your desired output suggests).

See proof-of-concept:

const recipesList = [
  {
    recipeId: 1,
    recipeTypeId: 1, // breakFast
    "description": "someRecipe",
    "img": "someImgBase64",
  },
  {
    recipeId: 2,
    recipeTypeId: 2, // lunch
    "description": "someRecipe",
    "img": "someImgBase64",
  },
  {
    recipeId: 3,
    recipeTypeId: 3, // snack
    "description": "someRecipe",
    "img": "someImgBase64",
  },
  {
    recipeId: 4,
    recipeTypeId: 4, // dinner
    "description": "someRecipe",
    "img": "someImgBase64",
  },
  {
    recipeId: 5,
    recipeTypeId: 1, // breakfast
    "description": "someRecipe",
    "img": "someImgBase64",
  }
];

// Collect unique recipeTypeId
const recipeTypes = new Set();
recipesList.forEach((recipe) => recipeTypes.add(recipe.recipeTypeId));

// Go through unique recipe types and return a randomly chosen recipe
const recipeCombos = Array.from(recipeTypes).map((type) => {
  const filteredRecipesByType = recipesList.filter((recipe) => {
    return recipe.recipeTypeId === type;
  });
  
  // Retrieve random recipe in this filtered collection
  const randomRecipeByType = filteredRecipesByType[Math.floor(Math.random() * filteredRecipesByType.length)];
  
  // Since you only want the recipeId, we return that property only
  return randomRecipeByType.recipeId;
});

// For your given data, the only possible combinations are:
// [1,2,3,4]
// [2,3,4,5]
console.log(recipeCombos.sort());
Terry
  • 63,248
  • 15
  • 96
  • 118
1

Explanations in a code snippet, please take a look

var recipes = [
  {
    recipeId: 1,
    recipeTypeId: 1, // breakFast
    "description": "someRecipe",
    "img": "someImgBase64",
  },
  {
    recipeId: 2,
    recipeTypeId: 2, // lunch
    "description": "someRecipe",
    "img": "someImgBase64",
  },
  {
    recipeId: 3,
    recipeTypeId: 3, // snack
    "description": "someRecipe",
    "img": "someImgBase64",
  },
  {
    recipeId: 4,
    recipeTypeId: 4, // dinner
    "description": "someRecipe",
    "img": "someImgBase64",
  },
  {
    recipeId: 5,
    recipeTypeId: 1, // breakfast
    "description": "someRecipe",
    "img": "someImgBase64",
  }
]

function randomRecipes(recipes) {
  // 1. taking a count of all the  different recipeTypeIds, it could be not always 4. could be 3, could be 5, so
  var recipeTypeIdsLegth = recipes.reduce((acc, item) => acc.indexOf(item.recipeTypeId) == -1 ? [...acc, item.recipeTypeId] : acc, []).length;
  console.log(recipeTypeIdsLegth) // 4

  // 2. clone original array, because we will play and modify it
  let clonedRecipes = [...recipes]

  // 3 declaring a result arrray
  var recommendedRandomRecipes = []

  // 4. create a loop
  for (i = 0; i < recipeTypeIdsLegth; i++) {
    
    // 5. randomindex
    var randomIndex = Math.floor(Math.random() * clonedRecipes.length);

    // 6. push recipe to result array
    recommendedRandomRecipes.push(clonedRecipes[randomIndex]);

    // 7. main magic. remove all the recipies with the same clonedRecipes[randomIndex].recipeTypeId from clonedRecipes
    clonedRecipes = clonedRecipes.filter(item => item.recipeTypeId !== clonedRecipes[randomIndex].recipeTypeId)
  }

  // 8. returning
  return recommendedRandomRecipes;
}

var recommendedRandomRecipes = randomRecipes(recipes);

console.log(recommendedRandomRecipes);
qiAlex
  • 4,290
  • 2
  • 19
  • 35