As you see in the data below, we have a list of restaurants,
each restaurant has a list of different menus,
and each menu has a list of products
my question is: how can I filter a restaurant based on the product object ?
so as you see the second product object (Typical salad) is missing the price so I want to remove the whole restaurant (Resturant 1) object from data, how can I do it?
const data = [
{
name: "Resturant 1",
phone: "0000555823",
multiple_menus: [
{
name: "salads",
products: [
{
name: "French salad",
price: 15.5
},
{
name: "Typical salad",
}
]
},
{
name: "burgers",
products: [
{
name: "cheese burger",
price: 15.5
},
{
name: "American burger",
price: 10
}
]
},
]
},
{
name: "Resturant 2",
phone: "0000555823",
multiple_menus: [
{
name: "salads",
products: [
{
name: "French salad",
price: 15.5
},
{
name: "Typical salad",
price: 5.5
}
]
}
]
},
]
As a more readable answer, this is a solution
const filteredData = data.filter((restaurant)=>{
const everyMenuProductHasPrice = restaurant.multiple_menus.every((menu)=>{
const everyProductHasPrice = menu.products.every((product)=>!!product.price)
return everyProductHasPrice
})
return everyMenuProductHasPrice
})
This question already has answers here:
Group array of objects by value and get count of the groups
(2 answers)
Closed last year.
I have an array of objects as follows :
let people = [
{ name: "Emily", age: 15 }, { name: "Emma", age: 16 },
{ name: "Stacy", age: 18 }, { name: "Emily", age: 15 },
{ name: "Jennifer", age: 12 }
];
I need to return the result containing the age as the key and frequency as it's corresponding value as follows :
{ 15 : 2, 16 : 1, 18 : 1, 12 : 1 }
I wish I could implement this using both forEach() and reduce().
Using Array#reduce:
const people = [ { name: "Emily", age: 15 }, { name: "Emma", age: 16 }, { name: "Stacy", age: 18 }, { name: "Emily", age: 15 }, { name: "Jennifer", age: 12 } ];
const ageCount = people.reduce((map, { age }) => ({
...map,
[age]: (map[age] || 0) + 1
}), {});
console.log(ageCount);
Related to my other question, where the image is How do I get rid of PROTOTYPE in my new JSON Object from an Array?
I want to be able to do the following:
Taking this one step further...
Each of those MARKET (name, displayName) which are both the same for now, have from 1 to "n" number of items within them.
So, I want to COUNT how many ITEMS are within or repeated.
For example:
NAME: "IL" may have 300
NAME: "WA" may have 1000
NAME: "OR" may have 100
and so on.
Inside these objects, the word MARKET is there. Market is what's above: IL, WA, CA, and so on are MARKETS like so:
[
{
ID: 1,
NAME: "SomeName1",
MARKET: "IL",
LOCATION: "6 Miles east"
},
{
ID: 2,
NAME: "SomeName2",
MARKET: "IL",
LOCATION: "36 Miles east"
},
{
ID: 3,
NAME: "SomeName3",
MARKET: "WA",
LOCATION: "3 Miles west"
},
{
ID: 4,
NAME: "SomeName4",
MARKET: "WA",
LOCATION: "33 Miles west"
},
{
ID: 5,
NAME: "SomeName5",
MARKET: "OR",
LOCATION: "23 Miles north"
},
...
]
I want to add a count to the MAP function I received as a solution:
const newObj = newMarketArray.map(e => ({ name: e, displayName: e }));
So that when the values appear as in the image above, I can get the number of occurrences of, WA, IL and OR for example.
The final JSON should have an additional element:
displayName: WA,
name: WA,
count: 33
And finally, I want to SORT the values of the JSON object which is probably very easy.
UPDATE: A question was raised that the MAP
const newObj = newMarketArray.map(e => ({ name: e, displayName: e }));
is false. That's not true. It returns the values in the IMAGE. So that is most certainly not false.
All I need is to COUNT the number of instances say, CA appears and place it like so:
const newObj = newMarketArray.map(e => ({ name: e, displayName: e, count: somecount }));
FYI: newMarketArray contains 3300+ objects
If i have well understood what you want:
newMarketArray = [
{
ID: 1,
NAME: "SomeName1",
MARKET: "IL",
LOCATION: "6 Miles east"
},
{
ID: 2,
NAME: "SomeName2",
MARKET: "IL",
LOCATION: "36 Miles east"
},
{
ID: 3,
NAME: "SomeName3",
MARKET: "WA",
LOCATION: "3 Miles west"
},
{
ID: 4,
NAME: "SomeName4",
MARKET: "WA",
LOCATION: "33 Miles west"
},
{
ID: 5,
NAME: "SomeName5",
MARKET: "OR",
LOCATION: "23 Miles north"
}
]
let objCount = newMarketArray.reduce((acc, obj) => {
acc[obj.MARKET] = (acc[obj.MARKET] || 0) + 1;
return acc;
}, {});
console.log(objCount);
let arrResult = Object.keys(objCount).map(k => ({'name': k, 'displayName': k, 'count': objCount[k] }));
console.log(arrResult)
After that, you could sort as you want the dictionary (by the value you want..)
I am confused with array inside object inside array, want to add a field inside presentsData call it sumP and inside get the sum of the value inside array presents using the array prices.
I tried reduce but it wasn't working, I tried with map and find and I am not getting a number I am getting an object, and can't figure out how to loop the both values
This is my code:
let presentsData= [
{
name: "Peter",
presents: ["coffee","holidays"],
money: 7000
},
{
name: "Mario",
presents: ["car","coal"],
money: 300
},
{
name: "Amanda",
presents: ["computer","coal"],
money: 300
},
{
name: "David",
presents: ["clothes", "car"],
money: 2000
}
]
const prices= [
{
present: "coffee",
price: 1
},
{
present: "holidays",
price: 1000
},
{
present: "videogames",
price: 40
},
{
present: "computer",
price: 600
},
{
present: "tattoo",
price: 30
},
{
present: "clothes",
price: 80
},
{
present: "car",
price: 6000
},
{
present: "phone",
price: 800
},
{
present: "motorbike",
price: 3500
}
]
const res = presentsData.map(s =>
({
...s,
sumP: prices.find(e=>e.present === s.presents[0] ? e.price: 0)
}));
console.log(res)
this is what I expected:
[
{
name: "Peter",
presents: ["coffee","holidays"],
money: 7000
sumP: (/*SUM OF PRESENTS'S VALUE*/)
},
{
name: "Mario",
presents: ["car","coal"],
money: 300
sumP: (/*SUM OF PRESENTS'S VALUE*/)
},
{
name: "Amanda",
presents: ["computer","coal"],
money: 300
sumP: (/*SUM OF PRESENTS'S VALUE*/)
},
{
name: "David",
presents: ["clothes", "car"],
money: 2000
sumP: (/*SUM OF PRESENTS'S VALUE*/)
}
]
Convert the prices to a Map or object of price by present. Iterate the data with Array.map(), and for each item reduce the presents to a number, taking the price from the prices Map.
const fn = (data, prices) => {
// creat a Map of price by present
const pricesMap = new Map(prices.map(({ present, price }) => [present, price]))
// map the data
return data.map(o => ({
...o,
// add sum by reducing the presents and taking the prices from the Map
sumP: o.presents.reduce((acc, p) => acc + (pricesMap.get(p) ?? 0), 0)
}))
}
const presentsData = [{"name":"Peter","presents":["coffee","holidays"],"money":7000},{"name":"Mario","presents":["car","coal"],"money":300},{"name":"Amanda","presents":["computer","coal"],"money":300},{"name":"David","presents":["clothes","car"],"money":2000}]
const prices = [{"present":"coffee","price":1},{"present":"holidays","price":1000},{"present":"videogames","price":40},{"present":"computer","price":600},{"present":"tattoo","price":30},{"present":"clothes","price":80},{"present":"car","price":6000},{"present":"phone","price":800},{"present":"motorbike","price":3500}]
const result = fn (presentsData, prices)
console.log(result)
Maybe someone can give me idea how can i do it. So I have array of names ["Tom", "Jane", "Mike", "John"] and also I have array of objects which are purchase reports:
[
{ date: "19/02/2019", name: "Mike", amount: 10 },
{ date: "20/02/2019", name: "Mike", amount: 15 },
{ date: "21/10/2019", name: "Jane", amount: 25 },
{ date: "22/03/2019", name: "John", amount: 30 },
{ date: "19/03/2019", name: "Tom", amount: 15 }
]
I need to get objects which represent a person and the amount they spend overall. [{ name: "Tom", amount: 15 }, { name: "Mike", amount: 25 }, ... I hope you get the idea. How can I achieve this? I try to map the names and filter array of objects but get undefined.
Use a combination of map, filter and reduce to boil down the data:
The first .map is building the object structure, you want e.g. {name: '...', amount: <val>}
in order to get the value for each of the names, you filter the spending by name and reduce the outputed values by adding them.
const names = ["Tom", "Jane", "Mike", "John"];
const spendings = [{
date: "19/02/2019",
name: "Mike",
amount: 10
}, {
date: "20/02/2019",
name: "Mike",
amount: 15
}, {
date: "21/10/2019",
name: "Jane",
amount: 25
}, {
date: "22/03/2019",
name: "John",
amount: 30
}, {
date: "19/03/2019",
name: "Tom",
amount: 15
}];
const result = names.map(name => {
return {
name,
amount: spendings.filter(spending => spending.name === name).reduce((sum, {
amount
}) => sum + amount, 0)
};
});
console.log(result);
You can try this code:
const data = [
{ date: "19/02/2019", name: "Mike", amount: 10 },
{ date: "20/02/2019", name: "Mike", amount: 15 },
{ date: "21/10/2019", name: "Jane", amount: 25 },
{ date: "22/03/2019", name: "John", amount: 30 },
{ date: "19/03/2019", name: "Tom", amount: 15 },
];
const names = ["Tom", "Jane", "Mike", "John"];
const results = names.map((name) => ({
name,
amount: data
.filter(({ name: dataName }) => dataName === name)
.reduce((total, { amount }) => total + amount, 0),
}));
console.log(results);
.as-console-wrapper { min-height: 100%!important; top: 0; }
You can set it up however you like using the javascript filter method.
Eg. If you want to get entries in the array that match name and amount you can write a function like this:
const result = (name, cost) => array.filter(customer => {
return name == customer.name && cost == customer.cost;
});
Running result("Jane", 25) will return this:
[{date: "21/10/2019", name: "Jane", amount: 25}]
You could create an object with the wanted names and add the amount to each property.
const
names = ["Tom", "Jane", "Mike", "John"],
purchases = [{ date:"19/02/2019", name: "Mike", amount: 10 }, { date: "20/02/2019", name: "Mike", amount: 15 }, { date: "21/10/2019", name: "Jane", amount: 25 }, { date: "22/03/2019", name: "John", amount: 30 }, { date: "19/03/2019", name: "Tom", amount: 15 }],
result = purchases.reduce(
(object, { name, amount }) => (object[name] += amount, object),
Object.fromEntries(names.map(name => [name, 0]))
);
console.log(result);
Use Array.reduce on your report array.
And reduce report array into dictionary of overall report for each name.
try first to solve it by your own.
this is my solution :
const dictionaryReports = reports.reduce((prev,curr)=>{
if(!prev[curr.name]) {
return {...prev,prev[curr.name] : curr}
}else{
return {
...prev,
prev[curr.name]:
{
...prev[curr.name],
amount : prev[curr.name].amount + curr.amount
}
}
}
},{})
the output will be :
dictionaryReports = {
Mike : {name:"Mike",amount:25},
Tom : {name:"Tom",amount:15}
}
then you can do
Object.values(dictionaryReports)
You can use the array reduce method on purchases. You don't need the array of names I think it looks useless for the result.
const purchases = [
{ date: "19/02/2019", name: "Mike", amount: 10 },
{ date: "20/02/2019", name: "Mike", amount: 15 },
{ date: "21/10/2019", name: "Jane", amount: 25 },
{ date: "22/03/2019", name: "John", amount: 30 },
{ date: "19/03/2019", name: "Tom", amount: 15 }
]
const overall = purchases.reduce((acc, curr) => {
const currentUser = acc.find(x => x.name === curr.name);
if(currentUser) {
currentUser.amount += curr.amount;
} else {
acc.push({name:curr.name,amount: curr.amount})
}
return acc;
}, []);
This approach is as generic as can be. It combines a map and a reduce method in a way that any data from a given dataset (list of data) and a corresponding (target) value list can be collected for the latter from the former by just providing a start configuration to the above mentioned map-reduce combination ...
const dataset = [
{ date: "19/03/2019", name: "Jerry", amount: 45 },
{ date: "19/02/2019", name: "Mike", amount: 10 },
{ date: "20/02/2019", name: "Mike", amount: 15 },
{ date: "21/10/2019", name: "Jane", amount: 25 },
{ date: "22/03/2019", name: "John", amount: 30 },
{ date: "19/03/2019", name: "Tom", amount: 15 },
{ date: "19/03/2019", name: "Jerry", amount: 15 }
];
function aggregateTargetItemValueFromSourceKey(collector, item) {
const { aggregateValue, sourceKey, targetKey, targetItem } = collector;
if (targetItem[targetKey] === item[targetKey]) {
targetItem[sourceKey] = aggregateValue(targetItem[sourceKey], item[sourceKey]);
}
return collector;
}
function createTargetItemFromBoundDatasetConfig(targetValue) {
const { dataset, aggregateValue, initialValue, sourceKey, targetKey } = this;
return dataset.reduce(aggregateTargetItemValueFromSourceKey, {
aggregateValue,
sourceKey,
targetKey,
targetItem: {
[targetKey]: targetValue,
[sourceKey]: initialValue
}
}).targetItem;
}
console.log(
["Tom", "Jane", "Mike", "John"]
.map(createTargetItemFromBoundDatasetConfig, {
aggregateValue: ((targetValue, sourceValue) => targetValue + sourceValue),
initialValue: 0,
sourceKey: 'amount',
targetKey: 'name',
dataset
})
);
console.log(
[5, 10, 15, 20, 25, 30, 35, 40, 45, 50]
.map(createTargetItemFromBoundDatasetConfig, {
aggregateValue: ((targetValue, sourceValue) => targetValue.concat(sourceValue)),
initialValue: [],
sourceKey: 'name',
targetKey: 'amount',
dataset
})
);
.as-console-wrapper { min-height: 100%!important; top: 0; }
The second approach is a straightforward one, thus it is less flexible in the result it does produce. Nevertheless, there is at least the option of plainly aggregating the data from any item in the provided dataset, or, as the OP unintentionally might have hinted by the provided name list, one can use the latter for filtering only those items from the dataset list that are actually feature one of its names. ...
const dataset = [
{ date: "19/03/2019", name: "Jerry", amount: 45 },
{ date: "19/02/2019", name: "Mike", amount: 10 },
{ date: "20/02/2019", name: "Mike", amount: 15 },
{ date: "21/10/2019", name: "Jane", amount: 25 },
{ date: "22/03/2019", name: "John", amount: 30 },
{ date: "19/03/2019", name: "Tom", amount: 15 },
{ date: "19/03/2019", name: "Jerry", amount: 15 }
];
const itemNameList = ["Tom", "Jane", "Mike", "John"];
function aggregateItemAmountByItemNameWithOptionalNameCeck(collector, item) {
const { checklist, index, list } = collector;
const itemName = item.name;
const isProceed = (!Array.isArray(checklist) || checklist.includes(itemName))
if (isProceed) {
let targetItem = index[itemName];
if (!targetItem) {
targetItem = index[itemName] = {
name: itemName,
amount: 0
};
list.push(targetItem);
}
targetItem.amount = targetItem.amount + item.amount;
}
return collector;
}
console.log(
'with name check ... ',
dataset.reduce(aggregateItemAmountByItemNameWithOptionalNameCeck, {
checklist: itemNameList,
index: {},
list: []
}).list
);
console.log(
'without name check ... ',
dataset.reduce(aggregateItemAmountByItemNameWithOptionalNameCeck, {
index: {},
list: []
}).list
);
.as-console-wrapper { min-height: 100%!important; top: 0; }