This question already has answers here:
Sum similar keys in an array of objects
(15 answers)
Closed 4 months ago.
I need to understand the simplest way of doing this. I've got an array of objects:
const data =
[
{
"_id": "63613c9d1298c1c70e4be684",
"NameFood": "Coca",
"count": 2
},
{
"_id": "63621f10b61f259b13cafe8e",
"NameFood": "Xa xi",
"count": 2,
},
{
"_id": "63654bf94b61091ae9c4bfd3",
"NameFood": "Cafe đen",
"count": 2,
},
{
"count": 1,
"_id": "63613c9d1298c1c70e4be684",
"NameFood": "Coca",
}
]
I expect the result: filter duplicate values by _Id and plus 'count'
const data =
[
{
"_id": "63613c9d1298c1c70e4be684",
"NameFood": "Coca",
"count": 3
},
{
"_id": "63621f10b61f259b13cafe8e",
"NameFood": "Xa xi",
"count": 2,
},
{
"_id": "63654bf94b61091ae9c4bfd3",
"NameFood": "Cafe đen",
"count": 2,
},
]
Can anybody explain it to me step by step, please?
Just using reduce() can do it
const data =
[
{
"_id": "63613c9d1298c1c70e4be684",
"NameFood": "Coca",
"count": 2
},
{
"_id": "63621f10b61f259b13cafe8e",
"NameFood": "Xa xi",
"count": 2,
},
{
"_id": "63654bf94b61091ae9c4bfd3",
"NameFood": "Cafe đen",
"count": 2,
},
{
"count": 1,
"_id": "63613c9d1298c1c70e4be684",
"NameFood": "Coca",
}
]
let result = data.reduce((a,c) =>{
let obj = a.find(i => i._id == c._id)
if(obj){
obj.count += c.count
}else{
a.push(c)
}
return a
},[])
console.log(result)
Related
This question already has answers here:
How to sort an array based on the length of each element?
(12 answers)
Closed 1 year ago.
I have an array like below, and I need to sort the array by the string length of name field.
for an example,
[
{
"_id": 10,
"name": "AAAAAA"
},
{
"_id": 11,
"name": "AA"
},
{
"_id": 12,
"name": "AAAA"
},
{
"_id": 13,
"name": "A"
},
{
"_id": 14,
"name": "AAAAAAAA"
}
]
I need the array like this,
[
{
"_id": 13,
"name": "A"
},
{
"_id": 11,
"name": "AA"
},
{
"_id": 12,
"name": "AAAA"
},
{
"_id": 10,
"name": "AAAAAA"
},
{
"_id": 14,
"name": "AAAAAAAA"
}
]
can any one help me out with this. Thanks.
This can be accomplished with the _.orderBy method:
_.orderBy(data, [({ name }) => name.length, 'name'], ['desc']);
Here is a break-down:
I threw some "B"s into the mix to show the secondary sorting (after length is compared). Sorting the length alone is not unique enough.
const data = [
{ "_id": 1, "name": "AAAAAA" },
{ "_id": 2, "name": "AA" },
{ "_id": 3, "name": "AAAA" },
{ "_id": 4, "name": "A" },
{ "_id": 5, "name": "AAAAAAAA" },
{ "_id": 6, "name": "BBBBBB" },
{ "_id": 7, "name": "BB" },
{ "_id": 8, "name": "BBBB" },
{ "_id": 9, "name": "B" },
{ "_id": 10, "name": "BBBBBBBB" }
];
const sorted = _.orderBy(
data, // Data to be sorted
[
({ name: { length } }) => length, // First, sort by length
'name' // Them sort lexicographically
], [
'desc', // Length (descending)
'asc' // This is implied, and could be removed
]
);
console.log(sorted);
.as-console-wrapper { top: 0; max-height: 100% !important; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.21/lodash.min.js"></script>
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 2 years ago.
Improve this question
I have an array of JSON objects and I want to merge the objects that have the same text together while finding the average of relevance and the sum of count across all of the same instances.
var keywords = [
{
"text": "service businesses",
"relevance": 0.626303,
"count": 1
},
{
"text": "service businesses",
"relevance": 0.87319,
"count": 5
},
{
"text": "service businesses",
"relevance": 0.05,
"count": 100
},
{
"text": "restaurants",
"relevance": 0.614567,
"count": 16
},
{
"text": "restaurants",
"relevance": 0.609875,
"count": 4
},
{
"text": "hotels",
"relevance": 0.594905,
"count": 1
},
I tried the solution posted here but, I am getting an output like this:
{
text: 'service businesses',
count: '[object Object][object Object]'
}
The output I am hoping for would look like this:
{
"text": "service businesses",
"relevance": 0.516497667,
"count": 106
},
{
"text": "restaurants",
"relevance": 0.612221,
"count": 20
},
{
"text": "hotels",
"relevance": 0.594905,
"count": 1
},
Any help is much appreciated!
Using Array.prototype.reduce, you can group the elements by the text and based on that group data, can get the output as follows.
var keywords = [{
"text": "service businesses",
"relevance": 0.626303,
"count": 1
},
{
"text": "service businesses",
"relevance": 0.87319,
"count": 5
},
{
"text": "service businesses",
"relevance": 0.05,
"count": 100
},
{
"text": "restaurants",
"relevance": 0.614567,
"count": 16
},
{
"text": "restaurants",
"relevance": 0.609875,
"count": 4
},
{
"text": "hotels",
"relevance": 0.594905,
"count": 1
}
];
const groupBy = keywords.reduce((acc, cur) => {
acc[cur.text] ? acc[cur.text] = {
...acc[cur.text],
count: acc[cur.text].count + cur.count,
relevance: [...acc[cur.text].relevance, cur.relevance]
} : acc[cur.text] = {
...cur,
relevance: [cur.relevance]
};
return acc;
}, {});
const output = Object.values(groupBy).map((item) => ({
...item,
relevance: item.relevance.reduce((acc, cur) => acc + cur, 0) / item.relevance.length
}));
console.log(output);
I ran it in two for loops and then calculated the relevance on the second loop.
I just kept track of the values in a normal object.
var keywords = [
{
"text": "service businesses",
"relevance": 0.626303,
"count": 1
},
{
"text": "service businesses",
"relevance": 0.87319,
"count": 5
},
{
"text": "service businesses",
"relevance": 0.05,
"count": 100
},
{
"text": "restaurants",
"relevance": 0.614567,
"count": 16
},
{
"text": "restaurants",
"relevance": 0.609875,
"count": 4
},
{
"text": "hotels",
"relevance": 0.594905,
"count": 1
}
]
const objectMerge = (arr) => {
let map = {};
for(let idx in arr){
const { text, relevance, count } = arr[idx];
if(!map[text]){
map[text] = {
count: 0,
relevance: []
}
}
map[text].count += count
map[text].relevance.push(relevance)
}
for(const key in map){
let lenOfRelevance = map[key].relevance.length
map[key].relevance = map[key].relevance.reduce((a,b) => a+b) / lenOfRelevance
}
return map
}
console.log(objectMerge(keywords))
This question already has answers here:
Group objects by property in javascript
(8 answers)
Closed 2 years ago.
let attributeSet = [{
"id": 1,
"value": 11
},
{
"id" : 1,
"value": 12
},
{
"id" : 1,
"value" : 13
},
{
"id": "2",
"value" : "Qwerty"
}
]
I want to combine all the value in values like this
attributeSet = [
{
"id": 1,
"value": [11, 12, 13]
},
{
"id": 2,
"value": "Qwerty"
}
]
I am using two for loops for comparing the ids and then pushing it into an array. Can someone suggest me any better way.
You can use reduce & inside callback check if the accumulator object have the key same as id of the object under iteration. If not then create the key and push value to it
let attributeSet = [{
"id": 1,
"value": 11
},
{
"id": 1,
"value": 12
},
{
"id": 1,
"value": 13
},
{
"id": "2",
"value": "Qwerty"
}
]
let newData = attributeSet.reduce((acc, curr) => {
if (!acc[curr.id]) {
acc[curr.id] = {
id: curr.id,
value: []
}
}
acc[curr.id].value.push(curr.value)
return acc;
}, {});
console.log(Object.values(newData))
I have a json below like this
[
{
"monthlyData": [
{
"dateYear": "2020-07",
"data": [
{
"id": "45bf4792-c5a5-44ed-b7e8-57557c4f30ee",
"date": "2020-07-13T00:00:00.000Z",
"transactionId": "160",
"amount": 70,
"active": 1,
"createdAt": "2020-07-14T02:55:43.988Z",
"updatedAt": "2020-08-14T02:55:43.988Z",
"version": 1
}
]
}
],
"hashId": "4"
},
{
"monthlyData": [
{
"dateYear": "2020-08",
"data": [
{
"id": "38fe3c68-e6aa-4c57-b4d7-dc6c4f597269",
"date": "2020-08-13T00:00:00.000Z",
"transactionId": "146",
"active": 1,
"createdAt": "2020-08-14T02:55:43.988Z",
"updatedAt": "2020-08-14T02:55:43.988Z",
"version": 1
}
]
}
],
"hashId": "5"
}
]
I have an array with list of month-year as
let datesArr = ['2020-08','2020-09','2020-10','2020-11','2020-07']
Now I want to pick a date from datesArr one by one and find if the date matches with dateYear column in whole JSON array. A copy of JSON array should be created for those dates are matched. I want to keep only those object whose dates are getting matched.
You can use array.filter
let originalArray = [
{
"monthlyData": [
{
"dateYear": "2020-07",
"data": [
{
"id": "45bf4792-c5a5-44ed-b7e8-57557c4f30ee",
"date": "2020-07-13T00:00:00.000Z",
"transactionId": "160",
"amount": 70,
"active": 1,
"createdAt": "2020-07-14T02:55:43.988Z",
"updatedAt": "2020-08-14T02:55:43.988Z",
"version": 1
}
]
}
],
"hashId": "4"
},
{
"monthlyData": [
{
"dateYear": "2020-08",
"data": [
{
"id": "38fe3c68-e6aa-4c57-b4d7-dc6c4f597269",
"date": "2020-08-13T00:00:00.000Z",
"transactionId": "146",
"active": 1,
"createdAt": "2020-08-14T02:55:43.988Z",
"updatedAt": "2020-08-14T02:55:43.988Z",
"version": 1
}
]
}
],
"hashId": "5"
}
];
let datesArr = ['2020-08','2020-09','2020-10','2020-11'];
let filtered = originalArray.filter(value => {
value.monthlyData = value.monthlyData.filter(md => {
return datesArr.includes(md.dateYear);
})
return value.monthlyData.length > 0;
})
console.log(JSON.stringify(filtered))
This example will print this below (if that is what you want):
[
{
"monthlyData": [
{
"dateYear": "2020-08",
"data": [
{
"id": "38fe3c68-e6aa-4c57-b4d7-dc6c4f597269",
"date": "2020-08-13T00:00:00.000Z",
"transactionId": "146",
"active": 1,
"createdAt": "2020-08-14T02:55:43.988Z",
"updatedAt": "2020-08-14T02:55:43.988Z",
"version": 1
}
]
}
],
"hashId": "5"
}
]
Edit for date object comparison
if datesArr is like
let datesArr = [new Date('2020-08'),new Date('2020-09')];
You can use array.some inside second filter
let filtered = originalArray.filter(value => {
value.monthlyData = value.monthlyData.filter(md => {
return datesArr.some(value1 => value1.getTime() === new Date(md.dateYear).getTime());
})
return value.monthlyData.length > 0;
})
And of course if original array has also Date object, you can discard
new Date(md.dateYear).getTime() use md.dateYear.getTime() instead
Edit for your comment:
I need to add those dates into monthData who has not matched with
datesArray with data as empty. what should i do.
You can use below code for that
let newArr = []
datesArr.forEach(date => {
let element = originalArray.find(value => {
value.monthlyData = value.monthlyData.filter(md => {
return date === md.dateYear;
})
return value.monthlyData.length > 0;
})
if (!element){
element = {
"monthlyData": [
{
"dateYear": date,
"data": []
}
],
"hashId": "something?"
}
}else {
// make a clone
element = JSON.parse(JSON.stringify(element))
}
newArr.push(element);
})
You can do it efficiently with Javascript's forEach
The code below extracts the information you require.
const bigTable = [{
"monthlyData": [{
"dateYear": "2020-07",
"data": [{
"id": "45bf4792-c5a5-44ed-b7e8-57557c4f30ee",
"date": "2020-07-13T00:00:00.000Z",
"transactionId": "160",
"amount": 70,
"active": 1,
"createdAt": "2020-07-14T02:55:43.988Z",
"updatedAt": "2020-08-14T02:55:43.988Z",
"version": 1
}]
}],
"hashId": "4"
},
{
"monthlyData": [{
"dateYear": "2020-08",
"data": [{
"id": "38fe3c68-e6aa-4c57-b4d7-dc6c4f597269",
"date": "2020-08-13T00:00:00.000Z",
"transactionId": "146",
"active": 1,
"createdAt": "2020-08-14T02:55:43.988Z",
"updatedAt": "2020-08-14T02:55:43.988Z",
"version": 1
}]
}],
"hashId": "5"
}
]
const datesArr = ['2020-08', '2020-09', '2020-10', '2020-11', '2020-07']
console.log("Version 1: a separate object for each dateYear")
datesArr.forEach(dateYear => {
console.log(dateYear+":-------------------");
bigTable.forEach(monthlyArray => {
monthlyArray.monthlyData.forEach(monthData => {
if (dateYear === monthData.dateYear) {
console.log(monthData)
}
})
})
})
console.log("Version 2: a single array with an element for each element of datesArr")
const output = datesArr.map(dateYear => bigTable.filter(monthlyObject =>
monthlyObject.monthlyData[0].dateYear=== dateYear
)
)
console.log(output)
Depending on exactly how you want it to compile the result, which is not unambiguous from your question, you should be able to adjust it to your needs.
Without an example of the output that you want, all we can do is guess what you mean.
So i have this data:
let data = [
{
"purchase_id": 1,
"product": [
{
"name": "A",
"id": 1,
"transactions": [
{
"price": 5,
"qty": 2
},
{
"price": 10,
"qty": 2
}
]
},
{
"name": "B",
"id": 2,
"transactions": [
{
"price": 3,
"qty": 4
}
]
}
]
},
{
"purchase_id": 2,
"product": [
{
"name": "C",
"id": 3,
"transactions": [
{
"price": 5,
"qty": 2
}
]
},
{
"name": "D",
"id": 4,
"transactions": [
{
"price": 3,
"qty": 4
}
]
}
]
}
]
And i want to flatten array from each data.product.transactions data:
"transactions": [
{
"price",
"qty"
}
]
Expected output is:
[
{
"purchase_id": 1,
"name": "A",
"id": 1,
"price": 5,
"qty": 2
},
{
"purchase_id": 1,
"name": "A",
"id": 1,
"price": 10,
"qty": 2
},
{
"purchase_id": 1,
"name": "B",
"id": 2,
"price": 3,
"qty": 4
},
{
"purchase_id": 2,
"name": "C",
"id": 3,
"price": 5,
"qty": 2
},
{
"purchase_id": 2,
"name": "D",
"id": 4,
"price": 3,
"qty": 4
},
]
I have tried to use object assign, reduce but my code doesn't work. Thank you
Use nested Array.map() to create the objects, and spread into Array.concat() to flatten the sub-arrays at each level:
const data = [{"purchase_id":1,"product":[{"name":"A","id":1,"transactions":[{"price":5,"qty":2},{"price":10,"qty":2}]},{"name":"B","id":2,"transactions":[{"price":3,"qty":4}]}]},{"purchase_id":2,"product":[{"name":"C","id":3,"transactions":[{"price":5,"qty":2}]},{"name":"D","id":4,"transactions":[{"price":3,"qty":4}]}]}];
const result = [].concat(...data.map(({ purchase_id, product }) =>
[].concat(...product.map(({ name, id, transactions }) =>
transactions.map((o) => ({
purchase_id,
name,
id,
...o
})
)))));
console.log(result);
If you want to avoid the temp sub-arrays, and the flattering, use nested Array.forEach() calls, and push the created objects to a predefined array:
const data = [{"purchase_id":1,"product":[{"name":"A","id":1,"transactions":[{"price":5,"qty":2},{"price":10,"qty":2}]},{"name":"B","id":2,"transactions":[{"price":3,"qty":4}]}]},{"purchase_id":2,"product":[{"name":"C","id":3,"transactions":[{"price":5,"qty":2}]},{"name":"D","id":4,"transactions":[{"price":3,"qty":4}]}]}];
const result = [];
data.forEach(({ purchase_id, product }) =>
product.forEach(({ name, id, transactions }) =>
transactions.forEach((o) => result.push({
purchase_id,
name,
id,
...o
})
)));
console.log(result);
var arr = [];
data.forEach(x => {
x.product.forEach(y => {
y.transactions.forEach(z => {
z["name"] = y.name;
z["id"] = y.id;
z["purchase_id"] = x.purchase_id;
arr.push(z);
});
})
});
console.log(arr);