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?
CodePudding user response:
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; }
CodePudding user response:
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)
CodePudding user response:
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 asresult. The latter, while iterating the array, gets build/accumulated programmatically with each newcategoryand/oritemName.
Destructure (each)
itemData's arrayitem.(Create and/or) Access the
categoryspecific array by using the Logical nullish assignment ...??=pushthe correct (depending ononSalestate) 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; }
