I have restaurant data array , I should make another array by grouping items by category that belongs to , I should convert this array :
[
{
"category": {
"title": "Appetizers",
},
"id": 1,
"price": "10",
"title": "Spinach Artichoke Dip",
},
{
"category": {
"title": "Appetizers",
},
"id": 2,
"price": "10",
"title": "Hummus",
},
{
"category": {
"title": "Salads",
},
"id": 3,
"price": "7",
"title": "Greek",
},
{
"category": {
"title": "Salads",
},
"id": 4,
"price": "9",
"title": "Beyn",
}
]
into a new array that should be as final result like this:
[{
"category": "Appetizers",
"items" : ["Spinach Artichoke Dip","Hummus"]
},
{
"category" : "Salads",
"items" :["Greek", "Beyn"]
}
]
I can't find how to do it could you please help
Lets say that your data is a constant called data
So you can do this:
const data = [
{
"category": {
"title": "Appetizers",
},
"id": 1,
"price": "10",
"title": "Spinach Artichoke Dip",
},
{
"category": {
"title": "Appetizers",
},
"id": 2,
"price": "10",
"title": "Hummus",
},
{
"category": {
"title": "Salads",
},
"id": 3,
"price": "7",
"title": "Greek",
},
{
"category": {
"title": "Salads",
},
"id": 4,
"price": "9",
"title": "Beyn",
}
];
const result = [];
data.forEach((item) => {
const category = item.category.title;
const title = item.title;
let foundCategory = result.find((c) => c.category === category);
if (foundCategory) {
foundCategory.items.push(title);
} else {
result.push({ category, items: [title] });
}
});
console.log(result);
Now your desired result will be stored in result
happy coding
const itemsToCategories = (itemsArr) => {
const store = {};
itemsArr.forEach(item => {
const categoryTitle = item.category.title;
if (!store[categoryTitle]) store[categoryTitle] = [];
store[categoryTitle].push(item.title);
});
return Object.entries(store).map(([category, items]) => ({ category, items}));
};
This solution should be a bit faster than the accepted answer for large data sets. The main difference is the use of an object (store) instead of an array, so lookups by the category title are more efficient. Then we build an array from that object at the end.
This does have more overhead than the accepted solution above, so for smaller data sets, this ends up being slower in comparison.
Related
I have this JSON response where I want to push "status": "pending", inside the nested Menu array, Please help how I can achieve this in Javascript.
[
{
"id": 1,
"status": "pending",
"menues": [
{
"title": "Coke",
"price": "200"
}
]
},
{
"id": 2,
"status": "delivered",
"menues": [
{
"title": "Pepsi",
"price": "120"
}
]
}
]
Here is what I want to achieve:
I just want to push the Staus key/value inside the Menu array
[
{
"id": 1,
"menues": [
{
"title": "Coke",
"price": "200",
"status": "pending",
}
]
},
{
"id": 2,
"menues": [
{
"title": "Pepsi",
"price": "120",
"status": "delivered",
}
]
}
]
You can go over the array, and for each item, go over the items in menues. Using the forEach method, this can even be done as a single statement:
arr = [
{
"id": 1,
"status": "pending",
"menues": [
{
"title": "Coke",
"price": "200"
}
]
},
{
"id": 2,
"status": "delivered",
"menues": [
{
"title": "Pepsi",
"price": "120"
}
]
}
];
arr.forEach(nested => {
nested.menues.forEach(menu => menu.status = nested.status);
delete nested.status
});
console.log(arr);
Maybe this is what you want? The following script creates a new nested array structure, leaving the original unchanged. Instead of deleting the status property from the outer object I limit the creation of properties in the newly created object to id and menues.
I changed this answer in response to OP's comment asking for ES5 and ES6 methods and the ... operator.
arr = [
{
"id": 1,
"status": "pending",
"menues": [
{
"title": "Coke",
"price": "200"
}
]
},
{
"id": 2,
"status": "delivered",
"menues": [
{
"title": "Pepsi",
"price": "120"
}
]
}
];
const res=arr.map(nested =>({ id:nested.id, menues:
nested.menues.map(menu =>({...menu,status:nested.status})) }));
console.log(res);
I am trying to learn javascript reduce and map an I came across some difficulties.
I have an array with the following format. The id of the parent is same as the location_id of the child. I need to group the array into a nested format.
arr = [
{
"id": 4583211,
"name": "Location 1",
"location_id": null,
},
{
"id": 7458894,
"name": "Location 12",
"location_id": 4583211
},
{
"id": 7463953,
"name": "Location 13",
"location_id": 4583211
},
{
"id": 80302210,
"name": "Location 121",
"location_id": 7458894
},
{
"id": 80302219,
"name": "Location 122",
"location_id": 7458894
},
{
"id": 7464314,
"name": "Location 131",
"location_id": 7463953
},
{
"id": 4583216,
"name": "Location 2",
"location_id": null,
},
{
"id": 3566353,
"name": "Location 21",
"location_id": 4583216
},
]
This array should be grouped as:
result = [
{
"id": 4583211,
"name": "Location 1",
"locations": [
{
"id": 7458894,
"name": "Location 12",
"locations": [
{
"id": 80302210,
"name": "Location 121"
},
{
"id": 80302219,
"name": "Location 122"
}
]
},
{
"id": 7463953,
"name": "Location 13",
"locations": [
{
"id": 7464314,
"name": "Location 131"
}
]
}
]
},
{
"id": 4583216,
"name": "Location 2",
"locations": [
{
"id": 3566353,
"name": "Location 21"
}
]
}
]
I tried to group it using the following method found on SO but it gives different result.
result = arr.reduce(function (r, a) {
r[a.location_id] = r[a.location_id] || [];
r[a.location_id].push(a);
return r;
}, Object.create(null));
You could do this using reduce and recursion you just need to check if parent is equal to current elements location_id.
const data = [{"id":4583211,"name":"Location 1","location_id":null},{"id":7458894,"name":"Location 12","location_id":4583211},{"id":7463953,"name":"Location 13","location_id":4583211},{"id":80302210,"name":"Location 121","location_id":7458894},{"id":80302219,"name":"Location 122","location_id":7458894},{"id":7464314,"name":"Location 131","location_id":7463953},{"id":4583216,"name":"Location 2","location_id":null},{"id":3566353,"name":"Location 21","location_id":4583216}]
function create(data, parent = null) {
return data.reduce((r, e) => {
if(parent == e.location_id) {
const o = { id: e.id, name: e.name }
const children = create(data, e.id);
if(children.length) o.locations = children;
r.push(o)
}
return r
}, [])
}
console.log(create(data))
This question already has answers here:
How can I access and process nested objects, arrays, or JSON?
(31 answers)
Closed 4 years ago.
I'm new to Javascript, ES6 , and i have hit the wall with this problem
This is the JSON that i'm getting from a webservice
{
"products": [
{
"id": 2,
"id_default_image": "21",
"price": "35.900000",
"name": [
{
"id": "1",
"value": "item 1"
},
{
"id": "2",
"value": "item 1 alternate name"
}
]
},
{
"id": 4,
"id_default_image": "4",
"price": "29.000000",
"name": [
{
"id": "1",
"value": "item 2"
},
{
"id": "2",
"value": "item 2 alternate name"
}
]
}
]
}
The name property in the above JSON is an array and i need only the value of the first element. The desired output would be like below
{
"products": [
{
"id": 2,
"id_default_image": "21",
"price": "35.900000",
"name": "item 1"
},
{
"id": 4,
"id_default_image": "4",
"price": "29.000000",
"name": "item 2"
}
]
}
I'm working on a react-native project. What would be the easiest way to achieve this? Any help would be greatly appreciated. Thanks.
Similar to Ele's answer but if you don't want to change the original object. You can use map to iterate over the product objects and return a new products array:
const data = {"products":[{"id":2,"id_default_image":"21","price":"35.900000","name":[{"id":"1","value":"item 1"},{"id":"2","value":"item 1 alternate name"}]},{"id":4,"id_default_image":"4","price":"29.000000","name":[{"id":"1","value":"item 2"},{"id":"2","value":"item 2 alternate name"}]}]};
const products = data.products.map(obj => ({ ...obj, name: obj.name[0].value }));
console.log(products);
Also used: spread syntax
Well, you can use the function forEach or a simple for-loop and assign the first value to the attribute name.
let obj = { "products": [ { "id": 2, "id_default_image": "21", "price": "35.900000", "name": [ { "id": "1", "value": "item 1" }, { "id": "2", "value": "item 1 alternate name" } ] }, { "id": 4, "id_default_image": "4", "price": "29.000000", "name": [ { "id": "1", "value": "item 2" }, { "id": "2", "value": "item 2 alternate name" } ] } ]}
obj.products.forEach(o => (o.name = o.name[0].value));
console.log(obj);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Try this
const productsArray = products.map((product, index) => {
const obj = {};
obj["id"] = product["id"];
obj["id_default_image"] = product["id_default_image"];
obj["price"] = product["price"],
obj["name"] = product.name[0].value;
return obj;
});
const obj = {};
obj.products = productsArray;
console.log(obj);//will print you the desired output you want
As an example - I've included a one element array that contains an object that has a Children key, which is an array of objects and each object also has its' own Children key that contains another array.
[
{
"Id": "1",
"Children": [
{
"Id": "2",
"Children": [
{
"Id": "10",
"DisplayName": "3-4",
},
{
"Id": "1000",
"DisplayName": "5-6",
},
{
"Id": "100",
"DisplayName": "1-2",
},
]
}
]
}
]
There is a second array of objects that I would like to compare the first array of objects to, with the intention of making sure that the first array is in the same order as the second array of objects, and if it is not - then sort until it is.
Here is the second array:
[
{
"Id": "1",
"Children": [
{
"Id": "2",
"Children": [
{
"Id": "100",
"DisplayName": "1-2",
},
{
"Id": "10",
"DisplayName": "3-4",
},
{
"Id": "1000",
"DisplayName": "5-6",
},
]
}
]
}
]
The data that this will run on can be up in the tens of thousands - so performance is paramount.
What I'm currently attempting is using a utility method to convert each element of the second array into a keyed object of objects e.g.
{
1: {
"Id": "1",
"Children": [
{
"Id": "2",
"Children": [
{
"Id": "4",
"DisplayName": "3-4",
},
{
"Id": "3",
"DisplayName": "1-2",
},
]
}
]
}
}
This allows fast look up from the top level. I'm wondering if I should continue doing this all the way down or if there is an idiomatic way to accomplish this. I considered recursion as well.
The order of the already sorted array is not based on Id - it is arbitrary. So the order needs to be preserved regardless.
Assuming same depth and all Id's exist in each level of each object use a recursive function that matches using Array#findIndex() in sort callback
function sortChildren(main, other) {
other.forEach((o, i) => {
if (o.children) {
const mChilds = main[i].children, oChilds = o.children;
oChilds.sort((a, b) => {
return mChilds.findIndex(main => main.Id === a.Id) - mChilds.findIndex(main => main.Id === b.Id)
});
// call function again on this level passing appropriate children arrays in
sortChildren(mChilds, oChilds)
}
})
}
sortChildren(data, newData);
console.log(JSON.stringify(newData, null, ' '))
<script>
var data = [{
"Id": "1",
"Children": [{
"Id": "2",
"Children": [{
"Id": "3",
"DisplayName": "1-2",
},
{
"Id": "4",
"DisplayName": "3-4",
},
]
}]
}]
var newData = [{
"Id": "1",
"Children": [{
"Id": "2",
"Children": [{
"Id": "4",
"DisplayName": "3-4",
},
{
"Id": "3",
"DisplayName": "1-2",
},
]
}]
}]
</script>
I have an Array of Objects, each containing Array and Objects, like so:
data = [{
"id": 10022,
"date": "2017-12-31T03:44:19.963808Z",
"bought_beats": [{
"id": 10034,
"beat": {
"id": 6334,
"name": "Glass",
"producer": {
"id": 23,
"display_name": "MadReal",
}
},
"license": {
"id": 10034,
"name": "Premium",
},
}, {
"id": 894,
"beat": {
"id": 6334,
"name": "Other Name",
"producer": {
"id": 25,
"display_name": "Other Name",
}
},
"license": {
"id": 10034,
"name": "Premium",
},
}]
}, {
"moredata": "stuff"
}]
And I need to filter the bought_beats property, and only return beat, if beat.producer.id === 23
This is what I have but it's clearly not working
data.forEach(order => {
return order.bought_beats.filter(item => item.beat.id === producerId)
})
===========
Edit1:
Trying this. It "works", but it also removed some properties (id & date) from each order object (which is each index of data), so I have objects that only contain the array of "bought_beats"
var res = data.map(item => item.bought_beats.filter(item => item.beat.producer.id === 23))
========
Edit2
This seems to be 1 solution, it maintains the array and object structure the same, while it removes those unwanted elements from the bought_beats array.
data.forEach(order => {
let elementToRemoveIndex = order.bought_beats.findIndex(item => item.beat.producer.id !== 23)
order.bought_beats.splice(elementToRemoveIndex, 1)
})
Thanks #Pac0 for the continuous help
use .find over data.bought_beats since its an array,
DEMO
var data = [{
"id": 10022,
"date": "2017-12-31T03:44:19.963808Z",
"bought_beats": [{
"id": 10034,
"beat": {
"id": 6334,
"name": "Glass",
"producer": {
"id": 23,
"display_name": "MadReal",
}
},
"license": {
"id": 10034,
"name": "Premium",
},
}, {
"id": 894,
"beat": {
"id": 6334,
"name": "Other Name",
"producer": {
"id": 25,
"display_name": "Other Name",
}
},
"license": {
"id": 10034,
"name": "Premium",
},
}]
}, {
"moredata": "stuff"
}];
var result = data.find(dat => dat.bought_beats.some(item => item.beat.producer.id === 23));
console.log(result);
If I understood correctly, this should be what you want :
// project each object to its bought_beats / beats part
var beatsArrays = data.filter(x => x.bought_beats).map(x => x.bought_beats);
// flatten the array of arrays of beats into a simple array of beats
var beats = [].concat.apply([],beatsArrays).map(x => x.beat);
// filter
var relevantBeats = beats.filter(item => item.producer.id === 23);
// serve with a cherry in a sugar-frost cocktail glass (happy new year ! )
console.log(relevantBeats);
Snippet :
data = [{
"id": 10022,
"date": "2017-12-31T03:44:19.963808Z",
"bought_beats": [{
"id": 10034,
"beat": {
"id": 6334,
"name": "Glass",
"producer": {
"id": 23,
"display_name": "MadReal",
}
},
"license": {
"id": 10034,
"name": "Premium",
},
}, {
"id": 894,
"beat": {
"id": 6334,
"name": "Other Name",
"producer": {
"id": 25,
"display_name": "Other Name",
}
},
"license": {
"id": 10034,
"name": "Premium",
},
}]
}, {
"moredata": "stuff"
}];
// project each object to its bought_beats / beats part
var beatsArrays = data.filter(x => x.bought_beats).map(x => x.bought_beats);
// flatten the array of arrays of beats into a simple array of beats
var beats = [].concat.apply([],beatsArrays).map(x => x.beat);
// filter
var relevantBeats = beats.filter(item => item.producer.id === 23);
// serve with a cherry in a sugar-frost cocktail glass (happy new year ! )
console.log(relevantBeats);
// for each order
data.forEach(order => {
// we loop thorugh the bought beats array
order.bought_beats.forEach((item, index) => {
// and if there's a beat from another producer, we remove it
if (item.beat.producer.id !== producerId) order.bought_beats.splice(index, 1)
})
})