Transform a javascript object to an array based on value of each key in the original object I have an object of ingredients to be added to a burger. Its structure is as follows:

Input

    ingredients: {
        salad: 1,
        cheese: 2,
        meat: 2,
    }


I want to transform it to an array of JSX elements. Each key in the original object has to be mapped to the number of JSX elements equivalent to the value of the ingredient in the ingredients objects. So the result array should look like so:

Output

[
    &lt;BurgerIngredient type="salad" /&gt;,
    &lt;BurgerIngredient type="cheese" /&gt;,
    &lt;BurgerIngredient type="cheese" /&gt;,
    &lt;BurgerIngredient type="meat" /&gt;,
    &lt;BurgerIngredient type="meat" /&gt;,
]


My solution is as follows:

function getBurgerIngredients() {
    const ingredientNames = Object.keys(props.ingredients);
    const transformedIngredients = ingredientNames.map( (ingredientName) =&gt; {
        let burgerIngredientElements = [];
        for(let i=0; i&lt;props.ingredients[ingredientName]; i++) {
            burgerIngredientElements.push(
                &lt;BurgerIngredient type={ingredientName} /&gt;
            )
        }
        return [...burgerIngredientElements]
    });

    return transformedIngredients;
}


I'm aware that it's not the most elegant solution. Can anyone suggest any improvement(s)?
const ingredientNames = Object.keys(props.ingredients);


Just be aware that anything that iterates/enumerates an object's keys (Object.keys, for-in, etc.) does not guarantee order. So it might not always be "salad, cheese, cheese, meat, meat" in the end. It just happens that most browsers iterate in the order they were created/added to the object, which is why it appears like so. If you want order, use an array to begin with.

    let burgerIngredientElements = [];
    for(let i=0; i&lt;props.ingredients[ingredientName]; i++) {
        burgerIngredientElements.push(
            &lt;BurgerIngredient type={ingredientName} /&gt;
        )
    }
    return [...burgerIngredientElements]


Also, I don't think this code is doing what you think it's doing. You're pushing to an existing array, then spreading it's contents into another array. You're essentially just shallow-cloning. It might look rendered correctly (probably because JSX now does fragments) but the structure is questionable.



Anyways, a more functional way to iterate from 0 to N is to create an array of N items (it doesn't matter what the values are) and operate on that array using array methods. One way this can be achieved is using Array and array.fill.

Also, instead of a loop and an outer variable holding an array, you can use array.reduce with the accumulator being that array. That way, you don't have that extra mutable variable.

Your code could look like this:

function getBurgerIngredients() {
  const ingredients = props.ingredients

  return Object.keys(ingredients).reduce((c, ingredientName) =&gt; {
    const range = Array(ingredients[ingredientName]).fill()

    return [...c, ...range.map(() =&gt; (&lt;BurgerIngredient type={ingredientName} /&gt;))]
  }, []);
}