I have a JSON file with a lot of category names in it. Each category can have subcategories or none. So what I try to do is create an array of category names for each level. When A category hasn't any subcategories then it should show the array from previous level.
2 Examples of outcome:
// Subcategory A has subcategories so it should show them
Example 1: Kitchen -> Subcategory A -> Subsubcategory A1
Subcategory B Subsubcategory A2
Subsubcategory A3 -> etcetc...
Subsubcategory A4
// Subcategory B hasn't any subcategories so it should show the categories from the previous level
Example 2: Kitchen -> Subcategory A
Subcategory B -> Subcategory A
Subcategory B
How do you do that? I'm looking for directions/examples...
My JSON looks like this (I cut out all unessecary stuff). Categories can go to 6 levels deep!!
shop": {
categories": {
"1944163": {
id": "1944163",
"title": "Kitchen",
subs": {
"1944122": {
id": "1944122",
"title": "Subcategory A",
subs": {
"1944182": {
id": "1944182",
"title": "Subsubcategory A1",
"1944152": {
id": "1944152",
"title": "Subsubcategory A2",
// etc etc
"1944123": {
id": "1944123",
"title": "Subcategory B",
// etc..
When it comes to the Jquery I don't come further then this:
$.getJSON('url?format=json', function(data){
$.each(data.shop.categories, function(i, category) {
var currentCatId = $('.sidebar-left .sidebar-box ul').find('li.active').data('catid');
if(category.id == currentCatId) {
if(category.subs) {
$.each(category.subs, function(i, category) {
$('.categories-breadcrumbs ul').append('<li>'+category.title+'</li>');
});
}
}
}
});
});
Here's how I might approach it, and it involves a drastic change to the structure of your data. It does, however, greatly simplify it.
In short you have a flat array of objects that contain id, parentId, and label properties. parentId is the important property as it links the objects without having to deep-nest the information.
var cats = [
{ id: 1, parentId: 0, label: 'Kitchen' },
{ id: 2, parentId: 0, label: 'Man Cave' },
{ id: 3, parentId: 1, label: 'Cooker' },
{ id: 4, parentId: 3, label: 'Hob' },
{ id: 5, parentId: 2, label: 'Moose head' },
{ id: 6, parentId: 2, label: 'Cognac' }
];
You can then use the following function to grab the objects for the correct level based on the id:
function getData(arr, id) {
return arr.filter(function (el) {
return el.parentId === id;
});
}
I've mocked a demo to show you how simple it is to use this data
Related
I have a json where one parent array, and every object of parent array there is another child array pozzles.
So what I want to do is, there is one key-value(title) of parent item I want to add in every item of child array.
Check this json screen shot to understand clear.
Is there any direct method available in js to do this ?
Considering this is your data
const data = [{ id: 1, title: "some", pozzles: [{ id: "1A" }, { id: "1B" }] }, { id: 2, title: "some2", pozzles: [{ id: "2A" }, { id: "2B" }] }];
data.forEach(d => {
d.pozzles.forEach(p => { p.title = d.title })
});
I've been looking at a problem for hours and failing to find a solution. I'm given an array of customer objects.
In each customer object is an array of friends.
In the array of friends is an object for each friend, containing some data, including a name key/value pair.
What I'm trying to solve for: I'm given this customers array and a customer's name. I need to create a function to find if this customer name is in any other customer's friend lists, and if so, return an array of those customer's names.
Below is a customer list. And as an example, one of the customers is Olga Newton. What the code should be doing is seeing that Olga Newton is a customer and is also in the friends lists of Regina and Jay, and should be returning an array of Regina and Jay.
I thought I could do this simply with a filter function, but because the friends list is an array with more objects, this is adding level of complexity for me I can't figure out.
Below is a customer array. The out put should be
['Regina', 'Jay']
and what I've gotten has either been
[{fullCustomerObj1}, {fullCustomerObj2}]
or
[ ]
What am I missing?
Here is the customer array:
var customers = [{
name: "Olga Newton",
age: 43,
balance: "$3,400",
friends: [{
id: 0,
name: "Justice Lara"
}, {
id: 1,
name: "Duke Patrick"
}, {
id: 2,
name: "Herring Hull"
}, {
id: 3,
name: "Johnnie Berg"
}]
}, {
name: "Regina",
age: 53,
balance: "$4,000",
friends: [{
id: 0,
name: "Cheryl Kent"
}, {
id: 1,
name: "Cynthia Wells"
}, {
id: 2,
name: "Gutierrez Waters"
}, {
id: 3,
name: "Olga Newton"
}]
}, {
name: "Jay",
age: 28,
balance: "$3,000",
friends: [{
id: 0,
name: "Cross Barnett"
}, {
id: 1,
name: "Raquel Haney"
}, {
id: 2,
name: "Olga Newton"
}, {
id: 3,
name: "Shelly Walton"
}]
}];
Use filter and map, please.
function friends(c, name){
return c.filter((a) => {
return a.friends.map(b => b.name).includes(name)
}).map(a => a.name);
}
console.log(friends(customers, "Olga Newton"));
// ['Regina', 'Jay']
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/filter
We look to an array (friends[]) inside anther (customers[]), So used two for loops, the first determine witch customer will look for his friends, and the second the array will search inside, then set if statement if the cust name is inside friends[]: adding the customer name to customerFriends[] array, At the end return the customerFriends[].
let cust = "Olga Newton"; // Get the customer name who you look for his friends.
const findFriend = (cust, arrs) => { // Create findFriend function.
let customerFriends = []; // Create an array to set the result to it.
for (let i = 0; i < arrs.length; i++) { // For each Customer.
for (const arr of arrs[i].friends) { // For each Friend.
if (arr.name === cust) { // Use Strict equality to find Customer name in friends[].
customerFriends.push(arrs[i].name); // Add the customer name to the customerFriends[].
}
}
}
return customerFriends;// Return the final results.
}
console.log(findFriend(cust, customers)); // Call the function.
I have the following object:
"data": [
{
"label": "dataName",
"sections": [
{
"label": "label sections 1",
"fields": [
{
"id": 1,
"name": "field 1",
"value": "value field 1"
},
{
"id": 2,
"name": "field 2",
"value": "value field 2"
}
]
},
{
"label": "label sections 2",
"fields": [
{
"id": 5,
"name": "field 3",
"value": "value field 3"
}
]
}
]
I would like to create a new array by retrieving data from each field.
like this :
array [
{id: field.id, name: field.name, value: field.value }
{id: field.id, name: field.name, value: field.value }
]
I thought I would use each function like this :
_.each(data, function (elt) {
_.each(elt.ections, function (elt) {
....
})
});
but using the each function I should multiply the functions each.
Is there a solution to get the same result without using several functions each?
If you have a solution ?
Cordially
Use the reduce method:
var reduceSections = data.reduce((a,b) => (a.concat(b.sections)),[]);
var reduceFields = reduceSections.reduce((a,b) => (a.concat(b.fields)),[]);
var result = reduceFields;
console.log(result);
For more information, see
MDN JavaScript Reference - Array.prototype.reduce
MDN JavaScript Reference - Array.prototype.concat
The DEMO
var data = [{
"label": "dataName",
"sections": [{
"label": "label sections 1",
"fields": [{
"id": 1,
"name": "field 1",
"value": "value field 1"
},{
"id": 2,
"name": "field 2",
"value": "value field 2"
}]
},{
"label": "label sections 2",
"fields": [{
"id": 5,
"name": "field 3",
"value": "value field 3"
}]
}]
}];
var reduceSections = data.reduce((a,b) => (a.concat(b.sections)),[]);
var reduceFields = reduceSections.reduce((a,b) => (a.concat(b.fields)),[]);
var result = reduceFields;
console.log(result);
Only downside is that mutating the original data object will mutate the result in the array. (no shallow cloning)
That may or may not be a downside depending on the application.
If you want to clone the objects:
var clone = result.map(obj => Object.assign({},obj));
For more information, see
MDN JavaScript Reference - Object.assign
MDN JavaScript Reference - Array.prototype.map
As you are making use of lodash already, you have access to _.flatMap, _.map and _.clone.
Unfortunately, with your data structure, iterating over the arrays in your data is required, but with depending on what you are trying to achieve, there are alternatives to _.each.
Assuming you want to join all of cloned entries in fields, that are nested in each entry of the array sections, that are nested in each entry of the array data, you can use the following code:
function cloneFields(elt) { return _.map(elt.fields, _.clone) }
var allClonedFields = _.flatMap(data, elt => {
return _.flatMap(elt.sections, cloneFields);
});
The function cloneFields() is initialized outside of the loop for performance so that it isn't created on every iteration.
This code will pull out each entry in data, then from that entry pull out each entry in the sections key, then return the clone of each entry in the fields key and then join them into one large array giving the following result:
[ { id: 1, name: 'field 1', value: 'value field 1' },
{ id: 2, name: 'field 2', value: 'value field 2' },
{ id: 5, name: 'field 3', value: 'value field 3' } ]
If you don't know exactly how "deep" is your object i recommand you using recursive function. Here is what i suggest :
function recursivlyCreateObject(data) {
let result;
if(Array.isArray(data)) {
result = [];
data.forEach(function(element) {
result.push(recursivlyCreateObject(element));
});
} else {
result = {};
Object.keys(data).forEach(function(key) {
result[key] = data[key];
});
}
return result;
}
You can test it here
EDIT : note that this won't do much more than a simple console.log over the data but can help you about iterating an object recursivly
If i understand correctly, you're trying to get the fields property from each element in the array. To do this, take a look at array.map().
using array.map, you could do something like this:
let array = data.map(x => x.fields);
or:
let array = data.map(x => (
{id: x.fields.id,name: x.fields.name, value: x.fields.value }
));
https://www.w3schools.com/jsref/jsref_map.asp
I have an array of objects and an array of primitive values. I want to create a new array of objects that maps the values of the first to the latter.
Here's the array of objects:
var eventInstances = [
{
id: 1,
title: "Item 1"
},
{
id: 2,
title: "Item 2"
},
{
id: 1,
title: "Item 3"
},
{
id: 3,
title: "Item 4"
},
]
And the array of primitive values:
var dates = [1, 2, 3]
I want map the objects of eventInstances to a new Array of objects with the values of dateInstances as keys, which would correspond with the value of id in eventInstances.
The result should be:
var dateInstances = [
{
id: 1,
instances: [
{
title: "Item 1"
},
{
title: "Item 1"
}
]
},
{
id: 2,
instances: [
{
title: "Item 1"
},
{
title: "Item 1"
}
]
},
{
id: 3,
instances: [
{
title: "Item 2"
}
]
}
];
Sorry, if this is a newbie question, I've been reading up on sorting methods, but I'm quite at a loss here. Any hint would be highly appreciated. Thanks!
This function will give you your expected result.
dates.map(id=>{
return {id:id,
instances:eventInstances.filter(item =>{
return item.id === id;
})
.map(foundItem => {
return {title: foundItem.title}
})
}});
Might be a simpler way to do it, but here's what's happening. Use map to iterate through your dates array. Then filter to find items in eventInstances that match, then map through those again to just return the title.
Array.map docs
Array.filter docs
You actually don't need the second array, as all those id can be found in the data.
You could collect the data in a map keyed by id and then extract the values:
const eventInstances = [{id: 1,title: "Item 1"},{id: 2,title: "Item 2"},{id: 1,title: "Item 3"},{id: 3,title: "Item 4"}];
const map = new Map(eventInstances.map(({id}) => [id, {id, instances: []}]));
eventInstances.forEach(({id, title}) => map.get(id).instances.push({ title }));
const result = [...map.values()];
console.log(result);
This creates a Map from the data. The Map is populated using its constructor argument, which can accept an array of pairs as input. Such a pair will serve as key/value pair in the Map being constructed. The pairs that are given to the constructor look like this:
[id, {id, instances: []}]
And so the Map will have its keys set to ids and its values will be objects in the form {id, instances: []}. Duplicate id values will not result in extra entries... they will be ignored in the process.
The next step is the forEach loop, which puts values inside those instances properties.
Finally, the keys of the Map have served their purpose, they can now be ejected. We only need the values, which are turned into an array through the spread syntax.
I think you are looking for an object where the key equals to the id, and the value equals to an array of titles, like:
{
"0":[
"title1",
"title2"
],
"1":[
"title1",
"title2"
],
}
To achieve that you need:
var dateInstances = {};
for(let i =0; i<eventInstances.length;i++){
if (!Array.isArray(dateInstances[eventInstances[i]["id"]])){
dateInstances[eventInstances[i]["id"]] = [];
}
dateInstances[eventInstances[i]["id"]].push(eventInstances[i]["id"]["title"]);
}
I am trying to use Lodash to filter an array of objects based on a match of id's, this is what I have tried:
var team = _.find(this.teams, { 'id': this.newSchedule.team});
_.filter(this.yards, function(yard) {
return _.find(team.yards, { id: yard.id });
});
yards data:
[ { "id": 1, "name": "Test" },{ "id": 2, "name": "Test 2" } ]
team data:
[ { "id": 1, "name": "Team 1", "yards": [{ "id": 1, "name" }] ]
I want this.yards to show the yards based on the yard id from a selected team.
Its hard to understand what you mean, does the yard id match the team id?
If so it sounds like what you need to do is first find the team with the same id then grab that teams yards. Therefore I would use the map function twice:
const result = this
.yards
.map(y => team.find(t => t.id === y.id)) // join with the right team
.map(t => t.yards) // reduce to that teams yards
As team is an array, you need to iterate it before doing the _.find on an individual element in that array. It doesn't help that you called your variable team (singular). teams would make more sense.
Here is how you would change your lodash code:
var yards = [ { id: 1, name: "Test" },{ id: 2, name: "Test 2" } ],
teams = [ { id: 1, name: "Team 1", yards: [{ id: 1, name: "Missing string" }] } ]
result = _.filter(this.yards, function(yard) {
return _.some(this.teams, function(team) {
return _.find(team.yards, { id: yard.id });
});
});
console.log(result);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.16.4/lodash.min.js"></script>
So this returns the yards that are related to at least one team.