Related
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; }
How do you groupBy array of objects based on specific properties in vanilla javascript? For example this given:
const products = [
{
category: "Sporting Goods",
price: "$49.99",
stocked: true,
name: "Football"
},
{
category: "Sporting Goods",
price: "$9.99",
stocked: true,
name: "Baseball"
},
{
category: "Sporting Goods",
price: "$29.99",
stocked: false,
name: "Basketball"
},
{
category: "Electronics",
price: "$99.99",
stocked: true,
name: "iPod Touch"
},
{
category: "Electronics",
price: "$399.99",
stocked: false,
name: "iPhone 5"
},
{ category: "Electronics", price: "$199.99", stocked: true, name: "Nexus 7" }
];
i want to run a reduce function that would result to a new array of objects like this:
Intended Output:
const categorize = [
{
category:"Sporting Goods",
products: [
{
name:"Football",
price: "$49.99",
stocked: true
},
{
name:"Baseball",
price: "$9.99",
stocked: true
},
{
name:"Basketball",
price: "$29.99",
stocked: true
}
]
},
{
category: "Electronics",
products: [
{
name: "iPod Touch",
price: "$99.99",
stocked: true
},
{
name: "iPhone 5",
price: "$399.99",
stocked: false
},
{
name: "Nexus 7",
price: "$199.99",
stocked: true
}
]
}
]
i based my solution from the tutorial here: https://www.consolelog.io/group-by-in-javascript/ using the reduce function.
Here's my code:
const groupBy = (arr,prop)=>{
return arr.reduce((groups,item)=>{
let val = item[prop];
groups[val] = groups[val]||[];
groups[val].push(item);
return groups
},{});
}
const categorize = groupBy(products,'category');
console.log(categorize);
/* returns an Object like
Object {Sporting Goods: Array[3], Electronics: Array[3]}
however it's not the intended output.
*/
I tried to return Object.values(obj) or Object.entries(obj) inside the groupBy function but it just returns an array of 2 arrays like [Array[3],Array[3]] and if i set the initial value (2nd parameter of reduce) to empty [] instead of {}, the output is just an empty array. Need help, thanks!
Because you want an array containing objects (rather than just an array of plain values), create a { category, products: [] } object if it doesn't exist in the accumulator:
const products=[{category:"Sporting Goods",price:"$49.99",stocked:!0,name:"Football"},{category:"Sporting Goods",price:"$9.99",stocked:!0,name:"Baseball"},{category:"Sporting Goods",price:"$29.99",stocked:!1,name:"Basketball"},{category:"Electronics",price:"$99.99",stocked:!0,name:"iPod Touch"},{category:"Electronics",price:"$399.99",stocked:!1,name:"iPhone 5"},{category:"Electronics",price:"$199.99",stocked:!0,name:"Nexus 7"}];
const output = Object.values(
products.reduce((a, { category, ...item }) => {
if (!a[category]) {
a[category] = { category, products: [] };
}
a[category].products.push(item);
return a;
}, {})
);
console.log(output);
function (){
var map = {};
products.forEach((p) => {
if (map[p.category]) {
var c = p.category;
delete p.category;
map[c].push(p);
} else {
var c = p.category;
delete p.category;
map[c]=[c]
}
});
Object.keys(map).forEach((m) => {
ans.push({category:m, products: map[m]})
})
}
you can collect in one go products and map them.
Then make your resultinng array
I would like to know how to remove the object by property in nested array object
I have whole list of object in sampleobj, compare each id with apitrans, apifund, if success is false, remove obj in sampleobj
Remove the object if the success is false, in sampleobj.
I have tried:
var result = sampleobj.foreach(e=>{
if(e.id === "trans" && apitrans.success== true){
Object.assign(e, apitrans);
}
if(e.id === "fund" && apifund.success== true){
Object.assign(e, apifund);
}
// if success false remove the object.
})
//inputs scenario 1
var sampleobj=[{
id: "trans",
amount: "100",
fee: 2
},
{
id: "fund",
amount: "200",
fee: 2
}]
var apitrans =
{
success: true,
id: "trans",
tamount: "2000",
fee: "12"
}
var apifund =
{
success: false,
id: "fund",
tamount: "4000",
fee: "10"
}
//inputs scenario 2 how to do same if property name differs
if error, status error, or success false remove obj in sampleobj
var sampleobj=[{
id: "trans",
amount: "100",
fee: 2
},
{
id: "fund",
amount: "200",
fee: 2
},
{ id: "insta", amount: "400", fee: 2 }
]
var apitrans = {success: true,id: "trans",tamount: "2000",fee: "12"}
var apiinsta = { errors: [{code:"error.route.not.supported"}],id: "insta",tamount: "2000",fee: "12"}
var apifund = { status: "error", id: "fund", tamount: "4000", fee: "10" }
var sampleobj=[{
//Expected Output
result: [
{
id: "trans",
amount: "100",
fee: 2
}
]```
You can use filter() to remove elements from array.
Create a helper function(func) which takes two objects as parameter and compare id property of both and check success property of one of them.
Then use filter() of the given array and put both given objects array [apitrans,apifund].
Then use some() method on [apitrans,apifund] and check if any of them have id equal the current element using Helper Function.
var arr=[ { id: "trans", amount: "100", fee: 2 }, { id: "fund", amount: "200", fee: 2 } ]
var apitrans = {success: true,id: "trans",tamount: "2000",fee: "12"}
var apifund = { success: false, id: "fund", tamount: "4000", fee: "10" }
const func = (obj1,obj2) => obj1.id === obj2.id && obj2.success
const res = arr.filter(x => [apitrans,apifund].some(a => func(x,a)));
console.log(res)
You can filter out your array with conditions i.e filter gives you new array instead of changing the original array
var arr = [{
id: "trans",
amount: "100",
fee: 2
},
{
id: "fund",
amount: "200",
fee: 2
}
]
var apitrans = {
success: true,
id: "trans",
tamount: "2000",
fee: "12"
}
var apifund = {
success: false,
id: "fund",
tamount: "4000",
fee: "10"
}
var filter = arr.filter(function(item) {
//console.log(item);
if (item.id === apitrans.id && apitrans.success) {
return item
}
});
console.log(filter);
Or if you want an original array to be modified instead of getting a new array, you can use your given approach with some update i.e
var arr = [{
id: "trans",
amount: "100",
fee: 2
},
{
id: "fund",
amount: "200",
fee: 2
}
]
var apitrans = {
success: true,
id: "trans",
tamount: "2000",
fee: "12"
}
var apifund = {
success: false,
id: "fund",
tamount: "4000",
fee: "10"
}
arr.forEach(e => {
if (e.id === "trans" && apitrans.success == true) {
Object.assign(e, apitrans);
} else if (e.id === "fund" && apifund.success == true) {
Object.assign(e, apifund);
} else {
// if success false remove the object.
var index = arr.indexOf(e);
arr.splice(index, 1);
}
})
console.log("resulted original arr", arr)
I would like to know how to assign values to object property in nested object by id=insta in javascript
I have a two objects, I need apply one object property to another using javascript
I got stuck and dont know how to proceed,
obj1.forEach(e=> {if(e.id==='insta') Object.assign(e, obj2)})
var obj1 = [
{
id: "insta",
rate: "2.4",
fee: "0",
amount: "400"
},
{
id: "trans",
rate: "1.4",
fee: "0",
amount: "200"
}
]
var obj2 =
{
data: {
rate_value: "4.4",
fee_value: "10",
targetamount: "5000",
country_code: "SG"
}
}
Expected Output:
res= [
{
id: "insta",
rate: "4.4",
fee: "10",
amount: "5000",
country_code: "SG"
}
]
As your expected output shows you only want the items whose id="insta" so use filter() to get those. Then use map() and create a temporary object inside map. And return the combined object using Spread Operator.
Note: You need to create another object because properties name in obj2 and array are different.
var obj1 = [ { id: "insta", rate: "2.4", fee: "0", amount: "400" }, { id: "trans", rate: "1.4", fee: "0", amount: "200" }]
var obj2 = { data: { rate_value: "4.4", fee_value: "10", targetamount: "5000", country_code: "SG" } }
const res = obj1.filter(x => x.id === "insta").map(x => {
const {data} = obj2
let temp = {
rate : data.rate_value,
fee : data.fee_value,
amount : data.targetamount,
country_code : data.country_code
}
return {...x,...temp}
})
console.log(res)
We can use the reduce method to reduce the array to the result we intend to. Here I add the the if condition and mapping values from obj2 in the callback of the reduce method. Basically the filtering and mapping is done, inside the reduce callback method.
var obj1 = [{
id: "insta",
rate: "2.4",
fee: "0",
amount: "400"
},
{
id: "trans",
rate: "1.4",
fee: "0",
amount: "200"
}
]
var obj2 = {
data: {
rate_value: "4.4",
fee_value: "10",
targetamount: "5000",
country_code: "SG"
}
}
const result = obj1.reduce((acc, curr) => {
if (curr.id === 'insta') {
acc.push({
...curr,
rate: obj2.data.rate_value,
fee: obj2.data.fee_value,
amount: obj2.data.targetamount,
country_code: obj2.data.country_code
})
}
return acc;
}, []);
console.log(result);
First of all, you can Array.filter the array to contain object with id = "insta" then apply the data from obj2 to each one of the items using Array.map.
Something like that:
var obj1 = [{
id: 'insta',
rate: '2.4',
fee: '0',
amount: '400',
},
{
id: 'trans',
rate: '1.4',
fee: '0',
amount: '200',
},
];
var obj2 = {
data: {
rate_value: '4.4',
fee_value: '10',
targetamount: '5000',
country_code: 'SG',
},
};
const result = obj1
.filter(item => item.id === 'insta')
.map(item => ({
id: item.id,
rate: obj2.data.rate_value,
fee: obj2.data.fee_value,
amount: obj2.data.targetamount,
country_code: obj2.data.country_code,
}));
console.log(result)
I would like to know how to add existing matched values in object and add the remaining values in javascript
for example, i need to merge_obj with my_obj having id '1' , matched values targetAmount only replace and remaining properties need to add
I tried
var filtervalue = my_obj.filter((e)=>e.id == "1").map((e)=>Object.assign({},e[0], merge_obj));
const merge_obj = {
targetAmount: 50688.97,
type: "REGULAR"
}
const my_obj = [
{
id: "1",
logo: "img1.png",
name: "fund",
speed: "1 Days",
targetAmount: "2000"
},
{
id: "2",
logo: "img2.png",
name: "transfer",
speed: "1 Days",
targetAmount: "3000"
},
]
Expected Output:
var my_obj = [
{
id: "1",
logo: "img1.png",
name: "fund",
speed: "1 Days",
targetAmount: 50688.97,
type: "REGULAR",
},
{
id: "2",
logo: "img2.png",
name: "transfer",
speed: "1 Days",
targetAmount: "3000",
},
]
This can be achieved my using the array map method to iterate through the array of objects, checking if the id is equivalent to '1', followed by using ES6's spread syntax to 'merge' the objects.
const result = my_obj.map(obj => {
if (obj['id'] === '1') {
return {...obj, ...merge_obj}
} else {
return obj;
}
})
console.log(result)
Also, just a quick advice, try to use const and let instead of var!
Just merge the first one by checking id:
var my_obj = [{
id: "1",
logo: "img1.png",
name: "fund",
speed: "1 Days",
targetAmount: "2000"
},
{
id: "2",
logo: "img2.png",
name: "transfer",
speed: "1 Days",
targetAmount: "3000"
},
]
var merge_obj = {
targetAmount: 50688.97,
type: "REGULAR"
};
var new_obj = my_obj.map(e => {
if (e.id == "1") {
Object.keys(merge_obj).forEach(key => e[key] = merge_obj[key]);
}
return e;
});
console.log(new_obj);
.as-console-wrapper { max-height: 100% !important; top: auto; }
If you want to mutate the original just loop over your array and assign directly
var my_obj = [{
id: "1",
logo: "img1.png",
name: "fund",
speed: "1 Days",
targetAmount: "2000"
},
{
id: "2",
logo: "img2.png",
name: "transfer",
speed: "1 Days",
targetAmount: "3000"
},
]
var merge_obj = {
targetAmount: 50688.97,
type: "REGULAR"
};
my_obj.forEach(e=> {if(e.id==='1') Object.assign(e, merge_obj)})
console.log(my_obj)
Change the object accessor in the map function from e[0] to e only, and check if that works.
i.e.
var filtervalue = myList.filter((e)=>e.id == "1").map((e)=>Object.assign({}, e, merge_obj));
Also, you need to check your variable names properly whether its my_obj or myList.