Merging multiple JSON objects from an array together [closed] - javascript

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))

Related

How can I return an array of values from an array of grouped objects in js?

I have an array of subscriptions group by the type (basic,medium ...)
`
[
[
"Basic",
[
{ "id": 2, "name": "Basic", "started_at": "2022-01-24", "count": 4 },
{ "id": 2, "name": "Basic", "started_at": "2022-03-16", "count": 2 },
{ "id": 2, "name": "Basic", "started_at": "2022-05-16", "count": 1 }
]
],
[
"Medium",
[
{ "id": 3, "name": "Medium", "started_at": "2022-02-21", "count": 1 },
{ "id": 3, "name": "Medium", "started_at": "2022-05-28", "count": 1 }
]
],
[
"Premium",
[{ "id": 4, "name": "Premium", "started_at": "2022-04-21", "count": 1 }]
],
[
"Master",
[
{ "id": 7, "name": "Master", "started_at": "2022-07-28", "count": 1 },
{ "id": 7, "name": "Master", "started_at": "2022-08-02", "count": 1 }
]
],
[
"Jedi",
[{ "id": 6, "name": "Jedi", "started_at": "2022-09-28", "count": 1 }]
]
]
`
What I want to do is return an array containing objects foreach sub with the following data(get the count value by month):
`
[
{
label: "Basic",
data: [4, 0, 2, 0, 1,0],
},
{
label: "Medium",
data: [0, 1, 0, 0, 1,0],
},
...
]
`
The data field should contain the count field foreach subscription corresponding to the month. For example for with count 4 in January and count 2 in March it will return [4,0,1] with 0 for February.
How can I achieve that ?
I did this but it's returning only the existing month values so there is no way to know which month that value is for.
subscriptions.map((item) => {
return {
label: item[0],
data: item[1].map((value, index) => {
return value.count;
}),
};
})
You could reduce the array and create a mapper object which maps each plan with month specifc count. Something like this:
{
"Basic": {
"1": 4,
"3": 2,
"5": 1
},
"Medium": {
"2": 1,
"5": 1
},
...
}
Then loop through the entries of the object and create objects with plan as label and an array of length: 12 and get the data for that specific month using the index
const input=[["Basic",[{id:2,name:"Basic",started_at:"2022-01-24",count:4},{id:2,name:"Basic",started_at:"2022-03-16",count:2},{id:2,name:"Basic",started_at:"2022-05-16",count:1}]],["Medium",[{id:3,name:"Medium",started_at:"2022-02-21",count:1},{id:3,name:"Medium",started_at:"2022-05-28",count:1}]],["Premium",[{id:4,name:"Premium",started_at:"2022-04-21",count:1}]],["Master",[{id:7,name:"Master",started_at:"2022-07-28",count:1},{id:7,name:"Master",started_at:"2022-08-02",count:1}]],["Jedi",[{id:6,name:"Jedi",started_at:"2022-09-28",count:1}]]];
const mapper = input.reduce((acc, [plan, subscriptions]) => {
acc[plan] ??= {}
for(const { started_at, count } of subscriptions)
acc[plan][+started_at.slice(5,7)] = count
return acc;
}, {})
const output =
Object.entries(mapper)
.map( ([label, subData]) => ({
label,
data: Array.from({ length: 12 }, (_, i) => subData[i+1] ?? 0)
}) )
console.log(output)
Note:
This assumes that the data is for a single year only. If it can be across years you'd have to create another level of nesting:
{
"Basic": {
"2022": {
"1": 3
}
}
}
started_at.slice(5,7) is used to get the month number. If the dates are not in the ISO 8601 format, you can use new Date(started_at).getMonth() + 1 to get the month part.

How to sum the array values [duplicate]

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)

How can i make json file like this when i input

How can i make the cart_items like my expetation.. just it no more.. my problem just it :D
i just wanna make my cart_items like this.. hope you are can help me thanks. did I make the wrong method? and one more thing, i wanna make the qty inside the cart_items
this is my expectation
"cart": [
{
"id": 1,
"date": "12/10/2020",
"store": {
"id": 1,
"name": "Dirumah Aja",
"promo": 1
},
"cart_items": [
{
"id": 1,
"product": {
"id": 1,
"name": "Bakso Urat",
"price": 10000,
"promo": {
"nama": "promo"
}
},
"qty": 5
}
]
}
]
and this is what I got
"cart": [
{
"cart_items": {
"name": "Steak Sapi Impor",
"price": "38000",
"stock": "4",
"image": "https://firebasestorage.googleapis.com/v0/b/francise-fb70a.appspot.com/o/steak.jpg?alt=media&token=46e0d769-96d3-440f-8edb-5fce2481ace0",
"promo": 3,
"id": 8,
"qty": 1
},
"store": {
"name": "Amanda Foods Store",
"email": "amanda#food.com",
"store_image": "https://firebasestorage.googleapis.com/v0/b/francise-fb70a.appspot.com/o/full_hd_retina.jpeg?alt=media&token=3e602e86-661b-48ee-9e9c-af9f94a170d1",
"product": [
5,
7,
8,
2
],
"store_promo": 1,
"location": {
"street_name": "Jl. Kebon Gedang II B",
"province": "Jawa Barat",
"city": "Bandung",
"post_code": "40285"
},
"id": 1
},
"date_order": "Nov 03 2020 08:48:03",
"id": 2
}
]
This is my data
data() {
return {
promo_id: [],
promo_partner: [],
products: {},
qty: 1,
cart_items: [
{}
]
};
and this is my method
addToCart() {
const date = (new Date()).toString().split(' ').splice(1,4).join(' ')
this.products.cart_items = this.product;
this.products.cart_items.qty = this.qty;
this.products.store = this.partner;
this.products.date_order = date;
console.log(this.cart_items)
axios
.post("http://localhost:3000/cart/", this.products)
.then(() => {
swal("Belanja Berhasil!", {
icon: "success",
});
})
.catch((error) => console.log(error));
}
}
You need to use .push() to add items to an array. You're replacing the array with this.product.
if (!this.products.cart_items) { // initialize cart_items if necessary
this.products.cart_items = [];
}
this.products.cart_items.push({id: this.product.id, product: this.product, qty: this.qty});

filter nested array with Javascript

having an array with objects and inside an options array how do I filter the inner array of objects by key value?
Here is the following example:
let test = [{
"options": [{
"label": "Audi",
"value": 10
},
{
"label": "BMW",
"value": 18
},
{
"label": "Mercedes Benz",
"value": 116
},
{
"label": "VW",
"value": 184
}
],
"label": "test1"
},
{
"options": [{
"label": "Adler",
"value": 3664
},
{
"label": "Alfa Romeo",
"value": 3
},
{
"label": "Alpine",
"value": 4
}
],
"label": "test2"
}
]
how do I get back the object:
{
"label": "Audi",
"value": 10
}
if I filter with keyword Audi
return label.toLowerCase().includes(inputValue.toLowerCase());
I tried with the following
test.map((k) => {
res = k.options.filter((j) => {
inputValue.toLowerCase();
if (j.label.toLowerCase().includes(inputValue.toLowerCase())) {
return j;
}
});
});
You need to return the result of filter(), not just assign it to a variable, so that map() will return the results.
let test = [{
"options": [{
"label": "Audi",
"value": 10
},
{
"label": "BMW",
"value": 18
},
{
"label": "Mercedes Benz",
"value": 116
},
{
"label": "VW",
"value": 184
}
],
"label": "test1"
},
{
"options": [{
"label": "Adler",
"value": 3664
},
{
"label": "Alfa Romeo",
"value": 3
},
{
"label": "Alpine",
"value": 4
}
],
"label": "test2"
}
]
let inputValue = "audi";
let search = inputValue.toLowerCase();
let result = test.map(k => k.options.filter(j => j.label.toLowerCase().includes(search)));
console.log(result);
This will return all options matching the search query :
function find(array, query) {
return array.reduce((prev, current) => prev.concat(current.options), []).filter(item => item.label.includes(query))
}
find(test, 'Audi')
Use flatMap() followed by filter():
let test=[{options:[{label:"Audi",value:10},{label:"BMW",value:18},{label:"Mercedes Benz",value:116},{label:"VW",value:184}],label:"test1"},{options:[{label:"Adler",value:3664},{label:"Alfa Romeo",value:3},{label:"Alpine",value:4}],label:"test2"}]
let result = test.flatMap(el => {
return el.options.filter(car => car.label == "Audi")
})[0]
console.log(result)
You need to go two levels deep when traversing your array.
function filterArray(needle, haystack) {
return haystack
.map(h => h.options)
.flatMap(h => h )
.filter(h => h.label.toLowerCase().includes(needle.toLowerCase()));
CodeSandbox
This might gile your answer:
console.log(test[0].options[0]);

Extract objects from nested array of objects

I have the following data that is an array of nested objects:
"categories": [
{
"id": 1,
"name": "Category 1",
"years": [
{ "id": 1, "name": "1" },
{ "id": 2, "name": "2" }
]
},
{
"id": 2,
"name": "Category 2",
"years": [
{ "id": 2, "name": "2" },
{ "id": 3, "name": "3" }
]
}
]
I want to extract unique years in a separate array (desired output):
[
{ "id": 1, "name": "1" },
{ "id": 2, "name": "2" },
{ "id": 3, "name": "3" },
]
When I map out the years, I'm getting an array of arrays, how should I extract the unique objects for years?
let years = categories.map( (c) => { return c.years })
You can use a Map to filter duplicate years from the array of values using id as the key, and reduce() on both categories and years using the map as the accumulator:
const categories = [{
"id": 1,
"name": "Category 1",
"years": [
{ "id": 1, "name": "1" },
{ "id": 2, "name": "2" }
]
},
{
"id": 2,
"name": "Category 2",
"years": [
{ "id": 2, "name": "2" },
{ "id": 3, "name": "3" }
]
}
];
const years = categories.reduce(
(map, category) => category.years.reduce(
(map, year) => map.set(year.id, year),
map
),
new Map()
);
console.log([...years.values()]);
You can use reduce and Map
let data = [{"id": 1,"name": "Category 1","years": [{ "id": 1, "name": "1" },{ "id": 2, "name": "2" }]},{"id": 2,"name": "Category 2","years": [{ "id": 2, "name": "2" },{ "id": 3, "name": "3" }]}]
let final = data.reduce((op,{years}) => {
years.forEach(({id, name}) => {
let key = id + '-' + name
op.set(key, op.get(key) || {id, name})
})
return op
},new Map())
console.log([...final.values()])

Categories

Resources