Get element, remove duplicates and count total of each - javascript

I have the following list (object):
var data = [{
id: 1,
type: 'smartphone',
details: [{
brand: 'Samsung',
model: 'Galaxy A5'
}]
},
{
id: 2,
type: 'smartphone',
details: [{
brand: 'iPhone',
model: '6 plus'
}]
},
{
id: 3,
type: 'smartphone',
details: [{
brand: 'Samsung',
model: 'Galaxy A5'
}]
},
{
id: 4,
type: 'smartphone',
details: [{
brand: 'iPhone',
model: '7 plus'
}]
},
{
id: 5,
type: 'phone',
details: [{
brand: 'Nokia',
model: '3310'
}]
},
{
id: 6,
type: 'smartphone',
details: [{
brand: 'Samsung',
model: 'Galaxy A5'
}]
},
{
id: 7,
type: 'smartphone',
details: [{
brand: 'iPhone',
model: '6 plus'
}]
}
]
I try to show on the page a filtered list of phones and with the total amount of them using javascript/ angular
So on my page I want the following result:
Phone: Samsung, Model: Galaxy A5, Total: 3
Phone: iPhone, Model: 7 plus, Total: 1
Phone: iPhone, Model: 6 plus, Total: 2
Phone: Nokia, Model: 3310, Total: 1
I will render it using ngFor but not quite sure how to filter and count total of each model at the same time.
Thanks in advance!

You can use reduce() method to transform your data to one object or array of objects and also calculate total for each model and brand.
var data = [{"id":1,"type":"smartphone","details":[{"brand":"Samsung","model":"Galaxy A5"}]},{"id":2,"type":"smartphone","details":[{"brand":"iPhone","model":"6 plus"}]},{"id":3,"type":"smartphone","details":[{"brand":"Samsung","model":"Galaxy A5"}]},{"id":4,"type":"smartphone","details":[{"brand":"iPhone","model":"7 plus"}]},{"id":5,"type":"phone","details":[{"brand":"Nokia","model":"3310"}]},{"id":6,"type":"smartphone","details":[{"brand":"Samsung","model":"Galaxy A5"}]},{"id":7,"type":"smartphone","details":[{"brand":"iPhone","model":"6 plus"}]}]
var result = data.reduce((r, {details}) => {
details.forEach(({brand, model}) => {
let key = `${brand}|${model}`;
if(!r[key]) r[key] = {phone: brand, model, total: 0}
r[key].total++;
})
return r;
}, {})
console.log(Object.values(result))

You can use reduce to remove the duplicates..
var data = [{
id: 1,
type: 'smartphone',
details: [{
brand: 'Samsung',
model: 'Galaxy A5'
}]
},
{
id: 2,
type: 'smartphone',
details: [{
brand: 'iPhone',
model: '6 plus'
}]
},
{
id: 3,
type: 'smartphone',
details: [{
brand: 'Samsung',
model: 'Galaxy A5'
}]
},
{
id: 4,
type: 'smartphone',
details: [{
brand: 'iPhone',
model: '7 plus'
}]
},
{
id: 5,
type: 'phone',
details: [{
brand: 'Nokia',
model: '3310'
}]
},
{
id: 6,
type: 'smartphone',
details: [{
brand: 'Samsung',
model: 'Galaxy A5'
}]
},
{
id: 7,
type: 'smartphone',
details: [{
brand: 'iPhone',
model: '6 plus'
}]
}
]
var reduced = data.reduce((acc, eachElem) => {
var foundIndex = acc.findIndex((e) => {
return eachElem.type == e.type && eachElem.details[0].brand == e.details[0].brand && eachElem.details[0].model == e.details[0].model;
});
if (foundIndex === -1) {
eachElem["count"] = 1;
acc.push(eachElem);
}
else {
acc[foundIndex]['count']++
}
return acc;
}, [])
console.log(reduced);

Related

Recursively filter an array to check deeply nested objects in JavaScript

let data = [
{
id: 900,
name: 'bar',
slug: 'julep-mask',
status: 'publish',
categories: [{
id: 43,
name: 'Beauty',
slug: 'beauty',
categories: [{
id: 777,
name: 'Beauty',
slug: 'asdfghjkl',
categories: [{
id: 999999,
name: 'Antony',
slug: 'Moss',
}]
}]
}]
},
{
id: 700,
name: 'foo',
slug: 'julep-mask',
status: 'publish',
categories: [{
id: 43,
name: 'Beauty',
slug: 'beauty',
categories: [{
id: 777,
name: 'Beauty',
slug: 'asdfghjkl',
categories: []
}]
}]
},
{
id: 999,
name: 'foobar',
slug: 'julep-mask',
status: 'publish',
categories: [{
id: 43,
name: 'Beauty',
slug: 'beauty',
categories: [{
id: 777,
name: 'Beauty',
slug: 'asdfghjkl',
categories: [{
id: 12345678,
name: 'Jo',
slug: 'Bloggs',
}]
}]
}]
},
{
id: 11111,
name: 'fib',
slug: 'julep-mask',
status: 'publish',
categories: [{
id: 43,
name: 'Beauty',
slug: 'beauty',
categories: [{
id: 777,
name: 'Beauty',
slug: 'asdfghjkl',
categories: []
}]
}]
}];
Given this example data array. I need to remove any object where the final categories array is empty. So I would expect to have an array which looks like this [{ id: 999 }, { id: 900 }] as a result.
I've tried the following, but this only get's me to the second categories key and wouldn't work for continuously nested data.
const populatedCategories = categories.map(category => {
const categories = category.categories.filter(cat => cat. categories);
if (categories.length) {
return {
...category,
categories
};
}
return null;
}
).filter(p => p);
enter code here
const data = [{"id":900,"name":"bar","slug":"julep-mask","status":"publish","categories":[{"id":43,"name":"Beauty","slug":"beauty","categories":[{"id":777,"name":"Beauty","slug":"asdfghjkl","categories":[{"id":999999,"name":"Antony","slug":"Moss"}]}]}]},{"id":700,"name":"foo","slug":"julep-mask","status":"publish","categories":[{"id":43,"name":"Beauty","slug":"beauty","categories":[{"id":777,"name":"Beauty","slug":"asdfghjkl","categories":[]}]}]},{"id":999,"name":"foobar","slug":"julep-mask","status":"publish","categories":[{"id":43,"name":"Beauty","slug":"beauty","categories":[{"id":777,"name":"Beauty","slug":"asdfghjkl","categories":[{"id":12345678,"name":"Jo","slug":"Bloggs"}]}]}]},{"id":11111,"name":"fib","slug":"julep-mask","status":"publish","categories":[{"id":43,"name":"Beauty","slug":"beauty","categories":[{"id":777,"name":"Beauty","slug":"asdfghjkl","categories":[]}]}]}]
const f = o=>!o.categories || o.categories.length && o.categories.every(f)
console.log(data.filter(f))
console.log(data.filter(f).map(({id})=>({id})))

Merge item in array of object with the same ID on Javascript

this is how the object look:
let data = [
{
brandId: '12345',
brand: 'Adidas',
item: {
name: 'Adidas 1',
price: '200',
},
},
{
brandId: '12345',
brand: 'Adidas',
item: {
name: 'Adidas 2',
price: '230',
},
},
{
brandId: '7878',
brand: 'Nike',
item: {
name: 'Nike 1',
price: '305',
},
}
];
i want the item object will merge if the object have the same brandID :
let data = [
{
brandId: '12345',
brand: 'Adidas',
item: [
{
name: 'Adidas 1',
price: '200',
},
{
name: 'Adidas 2',
price: '230',
},
],
},
{
brandId: '7878',
brand: 'Nike',
item: {
name: 'Nike 2',
price: '316',
},
},
];
is there any javascript syntax or method to do this ? and with an explanation will be very nice, Thank You
(Assuming that your output is just a typo and name/price doesn't actually changes) You can use array reduce
let data = [
{
brandId: '12345',
brand: 'Adidas',
item: {
name: 'Adidas 1',
price: '200',
},
},
{
brandId: '12345',
brand: 'Adidas',
item: {
name: 'Adidas 2',
price: '230',
},
},
{
brandId: '7878',
brand: 'Nike',
item: {
name: 'Nike 1',
price: '305',
},
}
];
const mergedItems = data.reduce((acc, curr) => {
// check if current exist on the accumulator
const exist = acc.find(brand => brand.brandId === curr.brandId);
// if it does, add the item on it
if (exist) {
return acc.map((brand) => {
if (brand.brandId === exist.brandId) {
return {
...brand,
item: brand.item.concat(curr.item),
}
}
})
}
// if it doesnt, add it on accumulator, and make the item array
return acc.concat({
...curr,
item: [
curr.item
]
})
})
(I wrote the code manually and not tested)
You can simply achieve this result using Map
let data = [
{
brandId: "12345",
brand: "Adidas",
item: {
name: "Adidas 1",
price: "200",
},
},
{
brandId: "12345",
brand: "Adidas",
item: {
name: "Adidas 2",
price: "230",
},
},
{
brandId: "7878",
brand: "Nike",
item: {
name: "Nike 1",
price: "305",
},
},
];
const dict = new Map();
data.forEach((o) => {
dict.get(o.brandId)
? dict.get(o.brandId).item.push(o.item)
: dict.set(o.brandId, { ...o, item: [o.item] });
});
const result = [];
for (let [k, v] of dict) {
v.item.length === 1 ? result.push({ ...v, item: v.item[0] }) : result.push(v);
}
console.log(result);
/* This is not a part of answer. It is just to give the output fill height. So IGNORE IT */
.as-console-wrapper { max-height: 100% !important; top: 0; }

Filter the desired items in the array and display them

I want to use the array methods to find the cheapest food in the menu and display the foods whose price is higher than 10 along with the name and ID in the console. Thank you for your help.
let menu = [
{ id: 1, name: "Soda", price: 3.12, size: "4oz", type: "Drink" },
{ id: 2, name: "Beer", price: 6.50, size: "8oz", type: "Drink" },
{ id: 3, name: "Margarita", price: 12.99, size: "12oz", type: "Drink" },
{ id: 4, name: "Pizza", price: 25.10, size: "60oz", type: "Food" },
{ id: 5, name: "Kebab", price: 31.48, size: "42oz", type: "Food" },
{ id: 6, name: "Berger", price: 23.83, size: "99oz", type: "Food" },
];
It's not very complex, just read the array with a FOR loop and filter the data with an IF .. :)
var menu = [
{ id: 1, name: "Soda", price: 3.12, size: "4oz", type: "Drink" },
{ id: 2, name: "Beer", price: 6.50, size: "8oz", type: "Drink" },
{ id: 3, name: "Margarita", price: 12.99, size: "12oz", type: "Drink" },
{ id: 4, name: "Pizza", price: 25.10, size: "60oz", type: "Food" },
{ id: 5, name: "Kebab", price: 31.48, size: "42oz", type: "Food" },
{ id: 6, name: "Berger", price: 23.83, size: "99oz", type: "Food" },
];
var menu2 = []; // creates a new array to hold the results
for(var i = 0; menu[i]; i++){
if(menu[i].price > 10) menu2[menu2.length] = menu[i]; // If an item has a price greater than 10 then I copy it to the new menu
}
console.log(menu2); // Display the new menu with the filtered data in the console

How to find a value in an array of objects using JavaScript?

I want to:
Find the cheapest and most expensive food and drink.
Find the id and name of drinks and foods if their price is higher than 10.
My attempt:
let menu = [
{ id: 1, name: "Soda",price: 3.12,size: "4oz",type: "Drink" },
{ id: 2, name: "Beer", price: 6.50, size: "8oz", type: "Drink" },
{ id: 3, name: "Margarita", price: 12.99, size: "12oz", type: "Drink" },
{ id: 4, name: "Pizza", price: 25.10, size: "60oz", type: "Food" },
{ id: 5, name: "Kebab", price: 31.48, size: "42oz", type: "Food" },
{ id: 6, name: "Berger", price: 23.83, size: "99oz", type: "Food" }
]
I would be happy and thankful if anybody could help.Thanks in Advanced.
here is an example :
let menu = [
{ id: 1, name: "Soda",price: 3.12,size: "4oz",type: "Drink" },
{ id: 2, name: "Beer", price: 6.50, size: "8oz", type: "Drink" },
{ id: 3, name: "Margarita", price: 12.99, size: "12oz", type: "Drink" },
{ id: 4, name: "Pizza", price: 25.10, size: "60oz", type: "Food" },
{ id: 5, name: "Kebab", price: 31.48, size: "42oz", type: "Food" },
{ id: 6, name: "Berger", price: 23.83, size: "99oz", type: "Food" }
];
function getCheapest(array) {
return Math.min(...array.map(item => item.price));
}
function getExpensive(array) {
return Math.max(...array.map(item => item.price));
}
function getFoodsAndDrinksMoreThan(array, minVal = 10){
return array.filter(item => item.price > minVal).map(item => ({id: item.id, name: item.name}));
}
console.log(getCheapest(menu));
console.log(getExpensive(menu));
console.log(getFoodsAndDrinksMoreThan(menu));
The first one could be achieved with Array.prototype.reduce by comparing the first and second argument of the function you pass into it and returning the smaller one.
For 2. that sounds like a case for Array.prototype.filter to me.
Let me know if you need more guidance.

Merge & Group Two Javascript array of objects and Group

I have two arrays of objects. One array contains list of items, another array contains list of categories. I want to create a new array based on categoryIds. I tried using lodash. But, couldn't get the correct solution.
I can do this using looping. But, I am looking for more clean approach.
var items = [
{
id: '001',
name: 'item1',
description: 'description of item1',
categoryId: 'cat1'
},
{
id: '002',
name: 'item2',
description: 'description of item2',
categoryId: 'cat2'
},
{
id: '003',
name: 'item3',
description: 'description of item3',
categoryId: 'cat1'
},
{
id: '004',
name: 'item4',
description: 'description of item4'
}
];
var categories = [
{
id: 'cat1',
name: 'Category1'
},
{
id: 'cat2',
name: 'Category2'
}
];
Expected output
[
{
categoryId: 'cat1',
name: 'Category1',
items: [
{
id: '001',
name: 'item1',
description: 'description of item1',
categoryId: 'cat1'
},
{
id: '003',
name: 'item3',
description: 'description of item3',
categoryId: 'cat1'
}
]
},
{
categoryId: 'cat2',
name: 'Category2',
items: [
{
id: '002',
name: 'item2',
description: 'description of item2',
categoryId: 'cat2'
}
]
},
{
categoryId: '',
name: '',
items: [
{
id: '004',
name: 'item4',
description: 'description of item4'
}
]
}
]
https://jsfiddle.net/sfpd3ppn/
Thanks for the help
The following does the trick:
var items = [{ id: '001', name: 'item1', description: 'description of item1', categoryId: 'cat1' }, { id: '002', name: 'item2', description: 'description of item2', categoryId: 'cat2' }, { id: '003', name: 'item3', description: 'description of item3', categoryId: 'cat1' }, { id: '004', name: 'item4', description: 'description of item4' } ];
var categories = [ { id: 'cat1', name: 'Category1' }, { id: 'cat2', name: 'Category2' } ];
var output = categories.concat([{id:'',name:''}]).map(function(v) {
return {
categoryId: v.id,
name: v.name,
items: items.filter(function(o) {
return o.categoryId === v.id || !o.categoryId && !v.id;
})
};
});
console.log(output);
I start by using .concat() to create a new categories array that holds the original categories items plus an "empty" category. Then I .map() that array to return category objects with your desired output structure, each of which has an items array that is produced by .filter()ing the original items array.
(Note that the items arrays within the output contain references to the same objects that were in the original items input, not copies of them. If you wanted copies you could add another .map() after the .filter().)
You can accomplish the desired result using a reduce. We are going to start with the original categories array and reduce the items array into it.
var items = [
{ id: '001', name: 'item1', description: 'description of item1', categoryId: 'cat1' },
{ id: '002', name: 'item2', description: 'description of item2', categoryId: 'cat2' },
{ id: '003', name: 'item3', description: 'description of item3', categoryId: 'cat1' },
{ id: '004', name: 'item4', description: 'description of item4' }
];
var categories = [
{ id: 'cat1', name: 'Category1' },
{ id: 'cat2', name: 'Category2' }
];
// Lets add the empty category at the beginning. This simplifies the logic.
categories.push({ id: '', name: '' });
// This is a function that will return a function to be used as a filter later on
function createFilter (category) {
return function (item) {
return item.id === category;
};
}
var mergedSet = items.reduce(function (previous, current) {
// Get the category ID of the current item, if it doesn't exist set to empty string
var categoryId = current.categoryId || '';
// Find the cateogry that matches the category ID
var category = previous.find(createFilter(categoryId));
// If the items property doesn't exists (we don't have any items), create an empty array
if (!category.items) { category.items = []; }
// Add the item the category
category.items.push(current);
// Return the current value that will be used in the next iteration.
// Note, the initial value of previous will be the intial value of categories.
return previous;
}, categories);
console.log(mergedSet);
/* Output
[
{ id: 'cat1',
name: 'Category1',
items:
[ { id: '001',
name: 'item1',
description: 'description of item1',
categoryId: 'cat1' },
{ id: '003',
name: 'item3',
description: 'description of item3',
categoryId: 'cat1' }
]
},
{ id: 'cat2',
name: 'Category2',
items:
[ { id: '002',
name: 'item2',
description: 'description of item2',
categoryId: 'cat2'
}
]
},
{ id: '',
name: '',
items:
[ { id: '004',
name: 'item4',
description: 'description of item4' } ] }
]
*/
Assuming the variables categories and items are assigned as you defined above:
const keyedCategories = _(categories)
.concat({ id: '', name: '' })
.keyBy('id')
.value();
const groupedItems = _.groupBy(items, (item) => _.get(item, 'categoryId', ''));
const result = _.reduce(groupedItems, (acc, value, key) => {
const { id: categoryId, name } = keyedCategories[key];
return _.concat(acc, { categoryId, name, items: value });
}, []);

Categories