-1

After days of hairpulling, I decided to seek help:

  • I have an array of objects, one for each grocery store item. Each object has 3 properties: category (string for category of item), itemName (string for item itself), and onSale (boolean whether it's on sale or not):

    var itemData = [
    { category: 'fruit',  itemName: 'apple', onSale: false },
    { category: 'canned', itemName: 'beans', onSale: false },
    { category: 'canned', itemName: 'corn',  onSale: true  },
    { category: 'frozen', itemName: 'pizza', onSale: false },
    { category: 'fruit',  itemName: 'melon', onSale: true  },
    { category: 'canned', itemName: 'soup',  onSale: false },
    ];
    
  • I need to convert it into an object whose properties are the object categories. Each property is an array containing values in itemName that correspond to the property:

    {
    fruit:  ['apple', 'melon($)'],
    canned: ['beans', 'corn($)', 'soup'],
    frozen: ['pizza']
    };
    
  • When I try to do it, I end up with directionally correct values, except they're repeated:

    {
    fruit: [ 'apple', 'apple', 'melon', 'melon', 'melon' ],
    canned: [
      'beans', 'beans',
      'corn',  'corn',
      'corn',  'soup',
      'soup',  'soup'
    ],
    frozen: [ 'pizza', 'pizza' ]
    }
    
  • I spent hours trying to find out where I went wrong, to no avail. Here's my code:

    function organizeItems (array){
    //create output obj
    var output = {}
    //iterate over the array
    for(var i = 0; i < array.length; i++){
    
    //iterate over the object in the array
      for(var category in array[i]){
        //if value of category isn't in output add the value to output as an empty array
        if(output[array[i]["category"]] === undefined){
          output[array[i]["category"]] = [];
          //if not --> push the itemName to the category
        } else{
          output[array[i]["category"]].push(array[i]["itemName"])
        }
        } 
      }
    return output
    }
    

How can I avoid the repetition and end up with the correct values in the arrays?

  • Does this answer your question? [Group array items using object](https://stackoverflow.com/questions/31688459/group-array-items-using-object) – pilchard Jan 03 '22 at 16:31
  • @AbuVladdy ... At SO it is considered to be a nice gesture from the one who got help, to provide some feedback and/or vote on answers and/or accept the answer which was the most helpful in solving the OP's problem. – Peter Seliger Jan 07 '22 at 12:07

3 Answers3

0
for(var category in array[i]){...

You don't have to iterate through the entries of each object as that will add unnecessary elements to the array like in your output 'melon', 'melon', 'melon'


You can use Array.prototype.reduce:

const itemData = [
{ category: 'fruit',  itemName: 'apple', onSale: false },
{ category: 'canned', itemName: 'beans', onSale: false },
{ category: 'canned', itemName: 'corn',  onSale: true  },
{ category: 'frozen', itemName: 'pizza', onSale: false },
{ category: 'fruit',  itemName: 'melon', onSale: true  },
{ category: 'canned', itemName: 'soup',  onSale: false },
];

const object = itemData.reduce((acc,el) => (acc[el.category] ??= [], acc[el.category].push(el.itemName + (el.onSale ? '($)' : '')), acc), {})

console.log(object)
Ramesh Reddy
  • 10,159
  • 3
  • 17
  • 32
0

You could group by category and adjust itemName.

const
    itemData = [{ category: 'fruit',  itemName: 'apple', onSale: false }, { category: 'canned', itemName: 'beans', onSale: false }, { category: 'canned', itemName: 'corn',  onSale: true  }, { category: 'frozen', itemName: 'pizza', onSale: false }, { category: 'fruit',  itemName: 'melon', onSale: true  }, { category: 'canned', itemName: 'soup',  onSale: false }],
    result = itemData.reduce((r, { category, itemName, onSale }) => {
        itemName += onSale ? ' ($)' : '';
        (r[category] ??= []).push(itemName);
        return r;
    }, {});

console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Nina Scholz
  • 376,160
  • 25
  • 347
  • 392
0
  1. Utilize Array.prototype.reduce

    • make use of an initial value (as shown with the one line above linked example code).
    • for the OP's use case the initial value too is an empty object (literal) ... {} ... which inside the reducer function is referred to as result. The latter, while iterating the array, gets build/accumulated programmatically with each new category and/or itemName.
  2. Destructure (each) itemData's array item.

  3. (Create and/or) Access the category specific array by using the Logical nullish assignment ... ??=

  4. push the correct (depending on onSale state) form of a category item; for instance by utilizing a Template literal

var itemData = [
  { category: 'fruit',  itemName: 'apple', onSale: false },
  { category: 'canned', itemName: 'beans', onSale: false },
  { category: 'canned', itemName: 'corn',  onSale: true  },
  { category: 'frozen', itemName: 'pizza', onSale: false },
  { category: 'fruit',  itemName: 'melon', onSale: true  },
  { category: 'canned', itemName: 'soup',  onSale: false },
];

// // expected result ...
// {
//   fruit:  ['apple', 'melon($)'],
//   canned: ['beans', 'corn($)', 'soup'],
//   frozen: ['pizza']
// };

console.log(
  itemData.reduce((result, item) => {

    // destructure `itemData`'s array `item`.
    const { category, itemName, onSale } = item;

    // (create and/or) access the `category` specific array.
    const categoryArray = (result[category] ??= []);

    // push the correct (depending on `onSale` state) form of a category item.
    categoryArray.push(`${ itemName }${ (onSale === true) ? '($)' : '' }`);

    return result;
  }, {})
);
.as-console-wrapper { min-height: 100%!important; top: 0; }
Peter Seliger
  • 11,747
  • 3
  • 28
  • 37
  • Hi my friend. I couldn't upvote bc I'm new but I wanted to thank you! I didn't understand all of the answer as I'm only a beginner, but I now know how to do it. – Abu Vladdy Jan 13 '22 at 11:05
  • @AbuVladdy ... That's why I was mentioning more than just one possibility related to [*"What should I do when someone answers my question?"*](https://stackoverflow.com/help/someone-answers). It is not just the voting. [Accepting an answer](https://meta.stackexchange.com/questions/5234/how-does-accepting-an-answer-work#5235) is another thing. As much as providing feedback in general, like continue asking in case things remained unclear or just simply saying thanks. After all, I think, the majority of people who answer do not always want to just speak/talk into the dark. – Peter Seliger Jan 13 '22 at 13:51