Hot Categories / inventory checker - javascript

We were given this activity in school to find categories that has no more stocks. Hot categories should be unique and without repeating categories.
const items = [
{ id: 'tltry001', name: 'soap', stocks: 14, category: 'toiletries' },
{ id: 'tltry002', name: 'shampoo', stocks: 8, category: 'toiletries' },
{ id: 'tltry003', name: 'tissues', stocks: 0, category: 'toiletries' },
{ id: 'gdgt001', name: 'phone', stocks: 0, category: 'gadgets' },
{ id: 'gdgt002', name: 'monitor', stocks: 0, category: 'gadgets' }
];
Here is my code so far. I am only getting one category and cannot display the 2nd category with 0 stocks.
function findHotCategories(items) {
let ilen = items.length
for(let i = 0; i < ilen; i++){
if(items[i].stocks === 0){
let newArr = items[i].category
return [newArr]
}
}
};

// dont forget to UpVoted (:
const items = [
{ id: 'tltry001', name: 'soap', stocks: 14, category: 'toiletries' },
{ id: 'tltry002', name: 'shampoo', stocks: 8, category: 'toiletries' },
{ id: 'tltry003', name: 'tissues', stocks: 0, category: 'toiletries' },
{ id: 'gdgt001', name: 'phone', stocks: 0, category: 'gadgets' },
{ id: 'gdgt002', name: 'monitor', stocks: 0, category: 'gadgets' }
];
const emptyStocks = [];
for( let a in items ){ if( items[a].stocks < 1 ) emptyStocks.push(items[a]); }
console.log( emptyStocks );

You return in the loop so the function ends where it matches the first item.
You should return after the loop
const items = [
{ id: 'tltry001', name: 'soap', stocks: 14, category: 'toiletries' },
{ id: 'tltry002', name: 'shampoo', stocks: 8, category: 'toiletries' },
{ id: 'tltry003', name: 'tissues', stocks: 0, category: 'toiletries' },
{ id: 'gdgt001', name: 'phone', stocks: 0, category: 'gadgets' },
{ id: 'gdgt002', name: 'monitor', stocks: 0, category: 'gadgets' }
];
function findHotCategories(items) {
let newArr = [];
let ilen = items.length
for(let i = 0; i < ilen; i++){
if(items[i].stocks === 0){
newArr.push(items[i].category)
}
}
return [...new Set(newArr)];
}
console.log(findHotCategories(items));

Here it is:
const items = [
{ id: 'tltry001', name: 'soap', stocks: 14, category: 'toiletries' },
{ id: 'tltry002', name: 'shampoo', stocks: 8, category: 'toiletries' },
{ id: 'tltry003', name: 'tissues', stocks: 0, category: 'toiletries' },
{ id: 'gdgt001', name: 'phone', stocks: 0, category: 'gadgets' },
{ id: 'gdgt002', name: 'monitor', stocks: 0, category: 'gadgets' }
];
const totalStocks = items.reduce((acc, prev) => {
if (!acc[prev.category]) {
return { ...acc, [prev.category]: prev.stocks }
}
return { ...acc, [prev.category]: acc[prev.category] + prev.stocks }
}, {})
const emptyStocks = Object.keys(totalStocks).filter(key => totalStocks[key] === 0)
console.log(emptyStocks)

My short answer with using filter and map function.
function findHotCategories(items) {
const result = items.filter(e => e.stocks === 0).map(e => e.category);
return [...new Set(result)];
}

Related

How to change object value in array with objects with if/else in JS

I have an array with objects. I need to find item with current name and change it.
const example = [
{
id: '1234',
desc: 'sample1',
items: [
itemsName: [
{ id: 1, name: 'name1' },
{ id: 2, name: 'testItem2' }
],
id: 888,
]
},
{
id: '3456',
desc: 'sample2',
items: [
itemsName: [
{ id: 1, name: 'name2' },
{ id: 2, name: 'testItem3' }
],
id: 889,
]
},
I try to do in this way, but it's not working.
I get construction like (5) 
[Array(1), Array(1)]
instead of 
[{…}, {…}]
const findName = (name, changedName) => {
const result = example?.map((group) =>
group.items.map((group) =>
group.itemsName?.map((i) => {
if (i.name === name) return i.name === changedName;
return null;
})
)
);
}
findName('name1', 'name2')
let findName1 = (name, changedName) => {
const result = example?.map((group) =>
group.items.map((group) =>
group.itemsName?.map((i) => {
if (i.name === name) return i.name = changedName;
return null;
})
)
);
}
This will work with following object (your object declaration seems to be wrong)
const example = [
{
id: '1234',
desc: 'sample1',
items: [
{itemsName: [
{ id: 1, name: 'name1' },
{ id: 2, name: 'testItem2' }
],
id: 888,}
]
},
{
id: '3456',
desc: 'sample2',
items: [
{itemsName: [
{ id: 1, name: 'name2' },
{ id: 2, name: 'testItem3' }
],
id: 889,}
]
}]

How do I get the total sum of nested arrays in Reactjs?

I want to get the total price of nested arrays in a specific category e.g: Hot Drinks.
Here is a sample of what I have now, so I want to filter out and get the total price of Hot Drinks Category only.
[
{
totalPrice: 30,
_id: '6014fa4324e125599eaa72b5',
orderItems: [
{
_id: '6014fa4324e125599eaa747ss',
category: 'Breakfast',
name: 'food name 1',
price: 3,
qty: 1,
},
{
_id: '6014fa4324e125599eaa747s5',
category: 'Hot Drinks',
name: 'drink name 1',
price: 3,
qty: 5,
},
{
_id: '6014fa4324e125599eaa74767',
category: 'Hot Drinks',
name: 'drink name 2',
price: 4,
qty: 2,
},
],
},
{
totalPrice: 23,
_id: '6014fa4324e125599eaa7276e',
orderItems: [
{
_id: '6014fa4324e125599eaa747ss',
category: 'Hot Drinks',
name: 'drink name 1',
price: 3,
qty: 6,
},
],
},
]
You can apply a filter method on the array and then just add the values on the filtered array. Something like below:
let prod = [
{
totalPrice: 30,
_id: '6014fa4324e125599eaa72b5',
orderItems: [
{
_id: '6014fa4324e125599eaa747ss',
category: 'Breakfast',
name: 'food name 1',
price: 3,
qty: 1,
},
{
_id: '6014fa4324e125599eaa747s5',
category: 'Hot Drinks',
name: 'drink name 1',
price: 3,
qty: 5,
},
{
_id: '6014fa4324e125599eaa74767',
category: 'Hot Drinks',
name: 'drink name 2',
price: 4,
qty: 2,
},
],
},
{
totalPrice: 23,
_id: '6014fa4324e125599eaa7276e',
orderItems: [
{
_id: '6014fa4324e125599eaa747ss',
category: 'Hot Drinks',
name: 'drink name 1',
price: 3,
qty: 6,
},
],
},
];
function getPriceByCategory(category, products) {
let price = 0;
products.forEach(orders => {
orders.orderItems.filter(order => order.category == category).forEach(item => {
price += item.price;
});
});
return price;
}
const totalPrice = getPriceByCategory('Hot Drinks', prod);
alert(totalPrice);
Sample JS Fiddle: https://jsfiddle.net/sagarag05/qwzju53f/9/
const filterBy = 'Hot Drinks';
const items = [
{
totalPrice: 30,
_id: '6014fa4324e125599eaa72b5',
orderItems: [
{
_id: '6014fa4324e125599eaa747ss',
category: 'Breakfast',
name: 'food name 1',
price: 3,
qty: 1,
},
{
_id: '6014fa4324e125599eaa747s5',
category: 'Hot Drinks',
name: 'drink name 1',
price: 3,
qty: 5,
},
{
_id: '6014fa4324e125599eaa74767',
category: 'Hot Drinks',
name: 'drink name 2',
price: 4,
qty: 2,
},
],
},
{
totalPrice: 23,
_id: '6014fa4324e125599eaa7276e',
orderItems: [
{
_id: '6014fa4324e125599eaa747ss',
category: 'Hot Drinks',
name: 'drink name 1',
price: 3,
qty: 6,
},
],
},
]
const sumOf = (items, filterBy) => {
let totalPrice = 0;
items.forEach(item => {
item.orderItems.forEach(orderItem => {
if (orderItem.category === filterBy) {
totalPrice += orderItem.price;
}
})
})
return totalPrice;
}
console.log(sumOf(items, filterBy))
let sum = 0;
allOrders.forEach(order => {
order.orderItems.forEach(item => {
if(item.category=='Hot Drinks') {
sum+ = item.price * item.qty
}});
});
sum has the total price for Hot Drinks
Assuming you named that information as data:
Generate a big array of all the "orderItems"
For each of those elements sum the price if the category is "Hot Drinks"
const totalPrice = data
.reduce((acc, { orderItems }) => [...acc, ...orderItems], [])
.reduce((acc, { category, price }) => category === "Hot Drinks" ? acc + price : acc, 0);
console.log(totalPrice); // 10
Use flatMap and reduce or alternatively using forEach and destructuring
const total = (arr, text) =>
arr
.flatMap(({ orderItems }) => orderItems)
.reduce((acc, { category, price }) =>
(acc + (category === text ? price : 0)), 0);
// alternatively
const total2 = (arr, text, acc = 0) => {
arr.forEach(({ orderItems }) =>
orderItems.forEach(
({ category, price }) => (category === text && (acc += price))
)
);
return acc;
};
const data = [
{
totalPrice: 30,
_id: "6014fa4324e125599eaa72b5",
orderItems: [
{
_id: "6014fa4324e125599eaa747ss",
category: "Breakfast",
name: "food name 1",
price: 3,
qty: 1,
},
{
_id: "6014fa4324e125599eaa747s5",
category: "Hot Drinks",
name: "drink name 1",
price: 3,
qty: 5,
},
{
_id: "6014fa4324e125599eaa74767",
category: "Hot Drinks",
name: "drink name 2",
price: 4,
qty: 2,
},
],
},
{
totalPrice: 23,
_id: "6014fa4324e125599eaa7276e",
orderItems: [
{
_id: "6014fa4324e125599eaa747ss",
category: "Hot Drinks",
name: "drink name 1",
price: 3,
qty: 6,
},
],
},
];
console.log(total(data, 'Hot Drinks'))
console.log(total2(data, 'Hot Drinks'))

How to add a child node in a nested object at a particular position using javascript

I have a data structure as given below
ds: [
{ id: "0a12", pos: 0, name: "PH1" },
{
id: "8f83",
name: "PH2",
pos: 1,
children: [
{ id: "ll54", pos: 0, name: "L1" },
{
id: "97cs",
name: "L2",
pos: 1,
children: [
{ id: "80s3", pos: 0, name: "LL1" },
{ id: "2dh3", pos: 1, name: "LL2" },
],
},
],
},
{ id: "75fd", pos: 2, name: "PH3" },
{ id: "34jg", pos: 3, name: "PH4" },
],
I am creating a org chart wherein I have option to add a node to the left or right.
On clicking the node, I can get the node obj as an argument (ie) if I clicked on 'LL1' I can get that object, along with second arg called as type which will contain either 'left' or 'right'.
so now the type == 'left' then my resultant data structure should be like
ds: [
{ id: "0a12", pos: 0, name: "PH1" },
{
id: "8f83",
name: "PH2",
pos: 1,
children: [
{ id: "4", pos: 0, name: "L1" },
{
id: "5",
name: "L2",
pos: 1,
children: [
{ id: "36fd", pos: 0, name: "" }, // new node for type === 'left'
{ id: "80s3", pos: 1, name: "LL1" },
{ id: "2dh3", pos: 2, name: "LL2" },
],
},
],
},
{ id: "75fd", pos: 2, name: "PH3" },
{ id: "34jg", pos: 3, name: "PH4" },
],
and if type === 'right'
ds: [
{ id: "0a12", pos: 0, name: "PH1" },
{
id: "8f83",
name: "PH2",
pos: 1,
children: [
{ id: "4", pos: 0, name: "L1" },
{
id: "5",
name: "L2",
pos: 1,
children: [
{ id: "80s3", pos: 0, name: "LL1" },
{ id: "36fd", pos: 1, name: "" }, // new node for type === 'right'
{ id: "2dh3", pos: 2, name: "LL2" },
],
},
],
},
{ id: "75fd", pos: 2, name: "PH3" },
{ id: "34jg", pos: 3, name: "PH4" },
],
Note: for those nodes that don't have children we shouldn't initialize an empty array to children attribute
You can use Array.slice and spread operator to insert the new node into your array.
let data = [
{ id: '0a12', pos: 0, name: 'PH1' },
{
id: "8f83",
name: "PH2",
pos: 1,
children: [
{ id: '4', pos: 0, name: 'L1' },
{
id: '5',
name: 'L2',
pos: 1,
children: [
{ id: '80s3', pos: 0, name: 'LL1' },
{ id: '2dh3', pos: 1, name: 'LL2' },
],
},
],
},
{ id: '75fd', pos: 2, name: 'PH3' },
{ id: '34jg', pos: 3, name: 'PH4' },
];
function addNode(direction, idElement, ptr) {
const elementIndex = ptr.findIndex(x => x.id === idElement);
if (elementIndex === -1) {
// Go deeper
return ptr.map(x => x.children ? {
...x,
children: addNode(direction, idElement, x.children),
}: x);
}
const offset = direction === 'left' ? 0 : 1;
// Insert the new node in the correct position
const mutatedPtr = [
...ptr.slice(0, elementIndex + offset),
{ id: 'XXXX', pos: elementIndex + offset, name: '' },
...ptr.slice(elementIndex + offset),
];
// change the positions
mutatedPtr.forEach((x, xi) => {
x.pos = xi;
});
return mutatedPtr;
}
data = addNode('right', '75fd', data);
data = addNode('left', '75fd', data);
data = addNode('left', '2dh3', data);
data = addNode('right', '2dh3', data);
console.log(data);
This is a tree insertion problem. First you need to find the index to the anchor node and then insert a new node at index if type is "left" or index + 1 if type is "right". Here's a solution that works for your case. Note that you need to set the right "id" using whatever id generator you have.
ds = [
{ id: "0a12", pos: 0, name: "PH1" },
{
id: "8f83",
name: "PH2",
pos: 1,
children: [
{ id: "4", pos: 0, name: "L1" },
{
id: "5",
name: "L2",
pos: 1,
children: [
{ id: "80s3", pos: 0, name: "LL1" },
{ id: "2dh3", pos: 1, name: "LL2" }
]
}
]
},
{ id: "75fd", pos: 2, name: "PH3" },
{ id: "34jg", pos: 3, name: "PH4" }
];
// Returns parent & position
function findNode(childNodes, name) {
for (var ii = 0; ii < childNodes.length; ii++) {
let child = childNodes[ii];
if (child.name == name) {
return {
childNodes: childNodes,
index: ii
};
}
if (child.children) {
let result = findNode(child.children, name);
if (result) {
return result;
}
}
}
return null;
}
function rewritePositions(childNodes) {
for (var ii = 0; ii < childNodes.length; ii++) {
childNodes[ii].pos = ii;
}
}
function insertNode(name, type) {
let searchResult = findNode(ds, name);
if (!searchResult) {
return;
}
let index = searchResult.index;
let newPosition = type === "left" ? index : index + 1;
let newNode = { id: "todo: index", pos: newPosition, name: "" };
searchResult.childNodes.splice(newPosition, 0, newNode);
rewritePositions(searchResult.childNodes);
}

Duplicate objects in array of objects by count value

I am looking for a way to modify array of objects like this:
[
{
id: 1,
name: 'xyz',
count: 3,
},
{
id: 2,
name: 'aaa',
count: 2,
},
{
id: 6,
name: 'bbb',
count: 1,
},
]
Now I want to map it shomehow to receive new array of objects without count properties but with duplicated objects by its count value. We will have:
[
{
id: 1,
name: 'xyz',
},
{
id: 1,
name: 'xyz',
},
{
id: 1,
name: 'xyz',
},
{
id: 2,
name: 'aaa',
},
{
id: 2,
name: 'aaa',
},
{
id: 6,
name: 'bbb',
},
]
I tried to do it with map and reduce but it didn't work out as expected...
You could use a nested mapping with an outer Array#flatMap.
var data = [{ id: 1, name: 'xyz', count: 3 }, { id: 2, name: 'aaa', count: 2 }, { id: 6, name: 'bbb', count: 1 }],
result = data.flatMap(({ count, ...o }) =>
Array.from({ length: count }, _ => ({ ... o })));
console.log(result);
Nina Scholz solution works fine, if you want something easier to read:
var data = [{
id: 1,
name: 'xyz',
count: 3,
},
{
id: 2,
name: 'aaa',
count: 2,
},
{
id: 6,
name: 'bbb',
count: 1,
},
];
var output = [];
for (var i = 0; i < data.length; i++) {
var element = data[i];
for (var j = 0; j < element.count; j++) {
output.push({
id: element.id,
name: element.name
});
}
}
console.log(output);

Build Object Recursive

I have a Object which looks like the following obj.
var obj = [
{ id: 1, name: "animals" },
{ id: 2, name: "animals_cat" },
{ id: 3, name: "animals_dog" },
{ id: 4, name: "animals_weazle" },
{ id: 5, name: "animals_weazle_sand shadow weazle" },
{ id: 11, name: "fruits" },
{ id: 32, name: "fruits_banana" },
{ id: 10, name: "threes" },
{ id: 15, name: "cars" }
];
The Object should be converted into the following scheme:
var items = [
{ id: 11, name: "fruits", items: [
{ id: 32, name: "banana" }
]},
{ id: 10, name: "threes" },
{ id: 1, name: "animals", items: [
{ id: 2, name: "cat" },
{ id: 3, name: "dog" },
{ id: 4, name: "weazle", items: [
{ id: 5, name: "sand shadow weazle" }
]}
]},
{ id: 15, name: "cars" }
];
I tried a lot but unfortunately without any success. I did $.each on obj, did a split('_') on it and pushed it to items. But how can I do it for unlimited depth and push it into the right category?
I'm happy for any help.
Maybe this helps.
It works with Array.prototype.forEach for processing obj, Array.prototype.reduce for getting the right branch and Array.prototype.some for the right array element for inserting the new object.
This proposal works for sorted and consistent data.
var obj = [
{ id: 1, name: "animals" },
{ id: 2, name: "animals_cat" },
{ id: 3, name: "animals_dog" },
{ id: 4, name: "animals_weazle" },
{ id: 5, name: "animals_weazle_sand shadow weazle" },
{ id: 11, name: "fruits" },
{ id: 32, name: "fruits_banana" },
{ id: 10, name: "threes" },
{ id: 15, name: "cars" }
],
tree = [];
obj.forEach(function (a) {
var path = a.name.split('_'),
o = {};
o.id = a.id;
path.reduce(function (r, b) {
o.name = b;
r.some(function (c) {
if (c.name === b) {
c.items = c.items || [];
r = c.items;
return true;
}
});
return r;
}, tree).push(o);
});
document.write('<pre>' + JSON.stringify(tree, 0, 4) + '</pre>');
Update: Version for independent order of items.
var obj = [
{ id: 5, name: "animals_weazle_sand shadow weazle" },
{ id: 32, name: "fruits_banana" },
{ id: 1, name: "animals" },
{ id: 2, name: "animals_cat" },
{ id: 3, name: "animals_dog" },
{ id: 4, name: "animals_weazle" },
{ id: 11, name: "fruits" },
{ id: 10, name: "threes" },
{ id: 15, name: "cars" },
{ id: 999, name: "music_pop_disco_euro"}
],
tree = [];
obj.forEach(function (item) {
var path = item.name.split('_'),
o = tree;
path.forEach(function (a, i) {
var oo = { name: a, items: [] },
last = path.length - 1 === i,
found = o.some(function (b) {
if (b.name === a) {
if (last) {
b.id = item.id;
return true;
}
b.items = b.items || [];
o = b.items;
return true;
}
});
if (!found) {
if (last) {
o.push({ id: item.id, name: a });
} else {
o.push(oo);
o = oo.items;
}
}
});
});
document.write('<pre>' + JSON.stringify(tree, 0, 4) + '</pre>');

Categories