In the below data structure,
data = {
data: [{
areas: [{
sections: [{
rjf: [{
type: 'heading-1'
text: 'Sample Heading',
}]
},
{
rjf: [{
type: 'paragraph',
depth: 0,
text: 'This website is offered to you by:',
inlineStyleRanges: [],
inlineEntityRanges: []
},
{
"type": "ordered-list-item",
"text": "Ordered Item A",
},
{
"type": "unordered-list-item",
"text": "Ordered Item B",
},
{
type: 'paragraph',
depth: 0,
text: 'This website is offered to you by:',
inlineStyleRanges: [],
inlineEntityRanges: []
},
{
"type": "ordered-list-item",
"text": "Ordered Item A",
},
{
"type": "unordered-list-item",
"text": "Ordered Item B",
}
]
}
]
}]
}]
};
I'm trying to group all the type which as ordered-list-item & unordered-list-item into new object. Something like below,
{
"type": 'list',
"items": [
{
"type": "ordered-list-item",
"text": "Ordered Item A",
},
{
"type": "unordered-list-item",
"text": "Ordered Item B",
}
]
}
After so much treble, I came with the below solution. This works fine.
But having an issue, In rjf if ordered-list-item & unordered-list-item not found nothing should be happen unfortunately and empty list getting added to rjf.
Below is the code snippet, please help me to fix this issue.
const data = {
data: [{
areas: [{
sections: [{
rjf: [{
text: 'Sample Heading',
}]
},
{
rjf: [{
type: 'paragraph',
depth: 0,
text: 'This website is offered to you by:',
inlineStyleRanges: [],
inlineEntityRanges: []
},
{
"type": "ordered-list-item",
"text": "Ordered Item A",
},
{
"type": "unordered-list-item",
"text": "Ordered Item B",
},
{
type: 'paragraph',
depth: 0,
text: 'This website is offered to you by:',
inlineStyleRanges: [],
inlineEntityRanges: []
},
{
"type": "ordered-list-item",
"text": "Ordered Item A",
},
{
"type": "unordered-list-item",
"text": "Ordered Item B",
}
]
}
]
}]
}]
};
const moveToNewObject = (data) => {
const sections = data[0].areas[0].sections;
sections.forEach(data => {
let list = data.rjf;
let a = list.map((entry, index) => {
return { ...entry,
index,
use: entry.type !== 'unordered-list-item' && entry.type !== 'ordered-list-item'
}
}).filter(entry => entry.use).map((entry, index, entries) => {
const end = index < entries.length - 1 ? entries[index + 1].index : list.length - entry.index;
return [{
type: entry.type,
text: entry.text
}, {
type: 'list',
items: list.slice(entry.index + 1, entry.index + end)
}]
});
console.log(a);
});
}
console.log(moveToNewObject(data.data));
Your data has a very weird structure which makes it harder to be honest. The snippet below uses a function that uses map on all your sections, and if rjf type is 'unordered-list-item' or 'ordered-list-item', it moves it to a new rjf of type list as items. Hopefully it's what you wanted.
And here's a fiddle if you want clearer code formatting:
https://jsfiddle.net/qce2vLr3/
const data = {
data: [
{
areas: [
{
sections: [
{
rjf: [
{
text: 'Sample Heading',
}
]
},
{
rjf: [
{
type: 'paragraph',
depth: 0,
text: 'This website is offered to you by:',
inlineStyleRanges: [],
inlineEntityRanges: []
},
{
"type": "ordered-list-item",
"text": "Ordered Item A",
},
{
"type": "unordered-list-item",
"text": "Ordered Item B",
}
]
}
]
}
]
}
]
};
const moveToNewObject = (data) => {
const sections = data[0].areas[0].sections; // why is data an array?
return sections.map((section) => {
if (section.rjf) {
const looseItems = section.rjf.filter((rjf) => rjf.type && ['ordered-list-item', 'unordered-list-item'].includes(rjf.type));
if (looseItems.length) {
return {
rjf: [
...section.rjf,
{
type: 'list',
items: looseItems
}
].filter((rjf) => rjf.type && !['ordered-list-item', 'unordered-list-item'].includes(rjf.type))
}
}
return section;
}
return section;
})
}
data.data[0].areas[0].sections = moveToNewObject(data.data);
console.log(data.data);
UPDATE
Here's a solution that "groups" your lists by multiple headings: https://jsfiddle.net/pkLyd0gh/
const data = {
data: [
{
areas: [
{
sections: [
{
rjf: [
{
text: 'Sample Heading',
}
]
},
{
rjf: [
{
"type": "heading-1",
"text": "A title",
},
{
"type": "ordered-list-item",
"text": "Ordered Item A",
},
{
"type": "unordered-list-item",
"text": "Ordered Item B",
},
{
"type": "heading-2",
"text": "A title",
},
{
"type": "ordered-list-item",
"text": "Ordered Item C",
},
{
"type": "unordered-list-item",
"text": "Ordered Item D",
}
]
}
]
}
]
}
]
};
const reformattedSections = (data) => {
const sections = data[0].areas[0].sections;
const listItemTypes = ['unordered-list-item', 'ordered-list-item'];
return sections.map((section) => {
let lastHeadingIndex = -1;
return section.rjf.reduce((acc, current, index) => {
if (!current.type || !listItemTypes.includes(current.type)) {
lastHeadingIndex = acc.length;
return [...acc, current]
}
else {
let listObject = acc.find((el, i) => i > lastHeadingIndex && i < index && el.type === 'list');
if (!listObject) {
listObject = {
type: 'list',
items: [current]
}
return [...acc, listObject];
}
listObject.items = [...listObject.items, current];
return acc;
}
}, [])
})
}
data.data[0].areas[0].sections = reformattedSections(data.data);
console.log('sections', data.data);
slice is a method on array's not on objects. DATA in your code is an Object
const a ={a:1,b:2,c:3,d:4}
const b =[1,2,3,4]
//console.log(a.slice(1,3)) //this will return the error
console.log(b.slice(1,3))
Hope it helps.
Related
I'm trying to group an array of objects. The array should be grouped following this quote:
Group by type respecting the sequence.
Array I wish to group
var arrayObj = [
{ "type": "user", "text": "user1" },
{ "type": "user", "text": "user2" },
{ "type": "user", "text": "user3" },
{ "type": "clerk", "text": "clerk1" },
{ "type": "user", "text": "user4" },
{ "type": "clerk", "text": "clerk2" },
{ "type": "clerk", "text": "clerk3" },
{ "type": "user", "text": "user5" },
{ "type": "user", "text": "user6" }
];
The way I want it to be grouped:
var newArray = [
[
{type: "user", text: "user1"},
{type: "user", text: "user2"},
{type: "user", text: "user3"}
],
[
{type: "clerk", text: "clerk1"}
],
[
{type: "user", text: "user4"}
],
[
{type: "clerk", text: "clerk2"},
{type: "clerk", text: "clerk3"}
],
[
{type: "user", text: "user5"},
{type: "user", text: "user6"}
]
];
What i tried:
I'm trying to use a filter, but without success since it even groups, but it groups all that are of the same type without respecting the sequence I want (from the array above);
var arrayObj = [
{ "type": "user", "text": "user1" },
{ "type": "user", "text": "user2" },
{ "type": "user", "text": "user3" },
{ "type": "clerk", "text": "clerk1" },
{ "type": "user", "text": "user4" },
{ "type": "clerk", "text": "clerk2" },
{ "type": "clerk", "text": "clerk3" },
{ "type": "user", "text": "user5" },
{ "type": "user", "text": "user6" }
];
var newArray = [];
newArray.push(filtrarArray(arrayObj, 'clerk'));
newArray.push(filtrarArray(arrayObj, 'user'));
console.log(newArray);
function filtrarArray(array, type) {
return array.filter(function (val) {
return val.type === type;
});
}
The snippet below first sorts the array by type, which then makes it easy to loop through and group. Let me know if this solves your problem :)
EDIT
Just realized you didn't need sorting, so I commented the sort function out, but it's always there to be uncommented if you change your mind :)
const arrayObj = [
{ type: 'user', text: 'user1' },
{ type: 'user', text: 'user2' },
{ type: 'user', text: 'user3' },
{ type: 'clerk', text: 'clerk1' },
{ type: 'user', text: 'user4' },
{ type: 'clerk', text: 'clerk2' },
{ type: 'clerk', text: 'clerk3' },
{ type: 'user', text: 'user5' },
{ type: 'user', text: 'user6' },
];
const group = ar =>
ar
// .sort((a, b) => (a.type < b.type ? -1 : 1))
.reduce((newAr, obj, i) => {
if (0 === i) return [[obj]];
if (obj.type === newAr[newAr.length - 1][0].type)
return newAr[newAr.length - 1].push(obj), newAr;
return [...newAr, [obj]];
}, []);
const groupedAr = group(arrayObj);
console.log(groupedAr);
function groupConsecutive(arrayObj) {
if (arrayObj.length === 0) {
return [];
}
let matchedTypesIndex = 0;
let newArray = [
[
arrayObj[0]
]
];
let currentType = arrayObj[0]["type"];
let i = 1;
while (i < arrayObj.length) {
if (arrayObj[i]["type"] === currentType) {
newArray[matchedTypesIndex].push(arrayObj[i]);
} else {
currentType = arrayObj[i]["type"];
newArray.push([]);
matchedTypesIndex++;
newArray[matchedTypesIndex].push(arrayObj[i]);
}
i++;
}
return newArray;
}
This is probably not best pure solution but works as you need.
var arrayObj = [
{ "type": "user", "text": "user1" },
{ "type": "user", "text": "user2" },
{ "type": "user", "text": "user3" },
{ "type": "clerk", "text": "clerk1" },
{ "type": "user", "text": "user4" },
{ "type": "clerk", "text": "clerk2" },
{ "type": "clerk", "text": "clerk3" },
{ "type": "user", "text": "user5" },
{ "type": "user", "text": "user6" }
];
let lastType;
let arr = [];
let arrIndex = -1;
arrayObj.forEach(obj => {
if(obj.type == lastType) { // add item into last group array by index
arr[arrIndex].push(obj);
}
else { // or add new group array
lastType = obj.type;
arrIndex++;
arr.push([obj]);
}
})
console.log(arr);
See This solution it will work
var arrayObj = [
{ type: "user", text: "user1" },
{ type: "user", text: "user2" },
{ type: "user", text: "user3" },
{ type: "clerk", text: "clerk1" },
{ type: "user", text: "user4" },
{ type: "clerk", text: "clerk2" },
{ type: "clerk", text: "clerk3" },
{ type: "user", text: "user5" },
{ type: "user", text: "user6" },
];
let typeNow = arrayObj[0].type;
let res = [];
let resultArray = [];
arrayObj.forEach((obj, i) => {
if (obj.type == typeNow) {
resultArray.push(obj);
} else {
resultArray = [obj];
res.push(resultArray);
typeNow = obj.type;
}
if (i == arrayObj.length - 1) res.push(resultArray);
});
console.log(res);
This is best solution can i have
It seem unordred because of Browser auto order but if you try in js file it will work and ordred
I'm responding with another way I found to solve my problem. This is just one more way I decided to comment.
Let's go:
I'm traversing the arrayObjects array using the appropriate loop for arrays for...of and then checking if the variable I set for arrayObjects (loopArrObj) has a different value of type of the variable (typeValue), if it is inserted at the end of the new array (grouping) using the array method push an empty array and then assign the value of the loopArrObj(Ie, there will be in the array grouping array empty only for the values that are different).
So far so good, we have the first empty array. Next I'm defining this empty array with the push method the loopArrObj object in question, then we get the value through the console. I'm removing 1 from grouping.lengh so the loop assigns from 0 and not 1.
var arrayObjects = [
{ "type": "user", "text": "user1" },
{ "type": "user", "text": "user2" },
{ "type": "user", "text": "user3" },
{ "type": "clerk", "text": "clerk1" },
{ "type": "user", "text": "user4" },
{ "type": "clerk", "text": "clerk2" },
{ "type": "clerk", "text": "clerk3" },
{ "type": "user", "text": "user5" },
{ "type": "user", "text": "user6" }
];
let typeValue,
grouping = [],
loopArrObj;
for (loopArrObj of arrayObjects) {
if (loopArrObj.type !== typeValue) {
grouping.push([]);
typeValue = loopArrObj.type;
}
grouping[grouping.length - 1].push(loopArrObj);
}
console.log(grouping);
I have a huge object, with almost 50k lines.
I need to add in each object new key with the current path of the node
Example:
let obj = {
"title": "RESSONÂNCIA MAGNÉTICA DA COLUNA LOMBAR",
"data": [{
"title": "Método:",
"data": [{
"title": "Procedimento 1",
"data": [{
"title": "CONTRASTE"
},
{
"title": "CONTRASTE 2"
}
]
},
{
"title": "Procedimento 2",
"data": [{
"title": "CONTRASTE 3"
},
{
"title": "CONTRASTE 4"
}
]
}
]
}]
}
And I need to change my object to return this:
obj = {
"path": "$",
"title": "RESSONÂNCIA MAGNÉTICA DA COLUNA LOMBAR",
"data": [{
"path": "$.data.0",
"title": "Método:",
"data": [{
"path": "$.data.0.data.0",
"title": "Procedimento 1",
"data": [{
"path": "$.data.0.data.0.data.0",
"title": "CONTRASTE"
},
{
"path": "$.data.0.data.0.data.1",
"title": "CONTRASTE 2"
}
]
},
{
"path": "$.data.0.data.1",
"title": "Procedimento 2",
"data": [{
"path": "$.data.0.data.1.data.0",
"title": "CONTRASTE 3"
},
{
"path": "$.data.0.data.1.data.1",
"title": "CONTRASTE 4"
}
]
}
]
}]
}
If you notice, i added the key path inside each object for key data, with the current path of the node. This is what I need.
All my object are much bigger then this example, with much more nested objects
Performant version in case you have to deal with large files
const data = {
"title": "RESSONÂNCIA MAGNÉTICA DA COLUNA LOMBAR",
"data": [{
"title": "Método:",
"data": [{
"title": "Procedimento 1",
"data": [{
"title": "CONTRASTE"
},
{
"title": "CONTRASTE 2"
}
]
},
{
"title": "Procedimento 2",
"data": [{
"title": "CONTRASTE 3"
},
{
"title": "CONTRASTE 4"
}
]
}
]
}]
}
function PathUpdate(data, path) {
data.path = path;
const nd = data.data;
if (nd == null) return;
for (let i = 0; i < nd.length; i++) {
PathUpdate(nd[i], `${path}.data.${i}`);
}
}
console.log("before", { data });
PathUpdate(data, "$");
console.log("after", { data });
const data = {
title: "RESSONÂNCIA MAGNÉTICA DA COLUNA LOMBAR",
type: "template",
data: [
{
title: "Método:",
type: "top-level-component",
data: [
{
title: "Procedimento",
type: "navigation",
normal: "CONTRASTE",
checked: true,
data: [
{
type: "single-selection",
title: "CONTRASTE",
},
{
type: "single-selection",
title: "CONTRASTE 2",
},
],
},
{
title: "Procedimento 2",
type: "navigation",
normal: "CONTRASTE",
checked: false,
data: [
{
type: "single-selection",
title: "CONTRASTE 3",
},
{
type: "single-selection",
title: "CONTRASTE 4",
},
],
},
],
},
],
};
function addPathToObj(obj, path) {
obj.path = path;
for (const [key, value] of Object.entries(obj)) {
if (Array.isArray(value)) {
value.forEach((item, index) => {
addPathToObj(item, `${path}.data.${index}`);
});
}
}
}
addPathToObj(data, "$");
console.log(data);
In the below JSON structure,
[
{
"type": "heading-1",
"text": "A title",
},
{
"type": "ordered-list-item",
"text": "Ordered Item A",
},
{
"type": "unordered-list-item",
"text": "Ordered Item B",
},
{
"type": "heading-2",
"text": "A title",
},
{
"type": "ordered-list-item",
"text": "Ordered Item A",
},
{
"type": "unordered-list-item",
"text": "Ordered Item B",
}
];
I need to move all the type which as ordered-list-item & unordered-list-item into new object. Something like below,
{
"type": 'list',
"items": [
{
"type": "ordered-list-item",
"text": "Ordered Item A",
},
{
"type": "unordered-list-item",
"text": "Ordered Item B",
}
]
}
Most important is, I need to maintain the order
For example, ordered-list-item & unordered-list-item should be pushed inside new object until the type is matched.
So with the above Json structure, Below is the expected output
[
{
"type": "heading-1",
"text": "A title",
},
{
"type": "heading-2",
"text": "A title",
},
{
"type": 'list',
"items": [
{
"type": "ordered-list-item",
"text": "Ordered Item A",
},
{
"type": "unordered-list-item",
"text": "Ordered Item B",
}
]
},
{
"type": "heading-1",
"text": "A title",
},
{
"type": 'list',
"items": [
{
"type": "ordered-list-item",
"text": "Ordered Item A",
},
{
"type": "unordered-list-item",
"text": "Ordered Item B",
}
]
},
]
How can this be done ?
You can use array.filter on any array to create a new array matching the criteria (in the same order)
const orderedList = yourArray.filter(a => a.type === 'ordered-list-item');
const unOrderedList = yourArray.filter(a => a.type === 'unordered-list-item');
then just build up the new json object using your new filtered array(s).
function deconstruct(data) {
let index = -1;
const out = [];
data.forEach(entry => {
if (entry.type !== 'ordered-list-item' && entry.type !== 'unordered-list-item') {
// If the current entry's type prop is no (un)ordered-list-item
// We push it to the array and reset the index variable to -1
out.push(entry);
index = -1;
} else {
// Else, we check if index is -1. If it is, we push a new object
// And save its index to the index variable
if (index === -1) {
index = out.push({ type: 'list', items: [] }) - 1;
}
// Add the entry to the items of the current list
out[index].items.push(entry);
}
});
return out;
}
Here's another way of doing it:
data.map((entry, index) => {
return {...entry, index, use: entry.type !== 'unordered-list-item' && entry.type !== 'ordered-list-item'}
}).filter(entry => entry.use).map((entry, index, entries) => {
const end = index < entries.length -1 ? entries[index + 1].index : data.length - entry.index;
return [{type: entry.type, text: entry.text}, {type: 'list', items: data.slice(entry.index + 1, entry.index + end)}]
}).flat(2);
I am trying to assign values from the below "details" object to the each "model" in the "formFields" array.
Here is the details object
const details = {
criteriaName: "hello",
criteriaType: "type a",
description: "world"
}
Here is the formFields array
From the above details object I was trying to assign each value from each key to the each model from the formFields array
const formFields = [
{
"title": "Title 1",
"columns": 2,
"fields": {
"criteriaName": {
"type": "text",
"label": "Criteria Name",
"id": 'criteriaName',
"model": "",
"required": true,
"show": true,
"rules": [
v => !!v || 'Criteria Name is required',
]
},
"criteriaType": {
"type": "select",
"label": "Criteria type",
"id": "criteriaType",
"options": ['Dependent', 'Independent', 'Static'],
"model": "",
"required": true,
"rules": [
v => !!v || 'Criteria Type is required',
],
"show": true,
},
}
},
{
'title': "Title 2",
"columns": 1,
"fields": {
"description": {
"type": "description_notes",
"label": "Description",
"id": "description",
"required": false,
"model": '',
"show": true,
}
}
}
]
How can I achieve this?
Thank you.
formFields.forEach((form) => {
if (form.fields.criteriaName) form.fields.criteriaName.model = details.criteriaName;
if (form.fields.criteriaType) form.fields.criteriaType.model = details.criteriaType;
if (form.fields.description) form.fields.description.model = details.description;
})
This would make changes in original array.
You can read more about forEach here
if you want to create a new array with changes you can use:
let newFormFields = formFields.map((form) => {
if (form.fields.criteriaName) form.fields.criteriaName.model = details.criteriaName;
if (form.fields.criteriaType) form.fields.criteriaType.model = details.criteriaType;
if (form.fields.description) form.fields.description.model = details.description;
return form;
});
and you can read more about map here
welcome to Stack Overflow. The following code will probably do what you're asking for. It is a bit much to explain all the details but you can ask in the comments and read some of the documentation
const details = {
criteriaName: 'hello',
criteriaType: 'type a',
description: 'world',
};
const formFields = [
{
title: 'Title 1',
fields: {
criteriaName: {
id: 'criteriaName',
model: '',
},
criteriaType: {
id: 'criteriaType',
model: '',
},
},
},
{
title: 'Title 2',
fields: {
description: {
id: 'description',
model: '',
},
nonExisting: {
id: 'nonExisting',
model: 'this will not be replaced',
},
},
},
];
const result = formFields.map((formField) => ({
...formField,
fields: Object.entries(formField.fields).reduce(
(fields, [key, value]) =>
details[key]
? {
...fields,
[key]: { ...value, model: details[key] },
}
: fields,
formField.fields,
),
}));
console.log(result);
I have these kind of data structure from an API, and they told me to group them accordingly.
INPUT
{
0: {
id: 0,
name: 'foo',
categories: [
'Category001',
'Category002/sub-category001'
]
},
1: {
id: 1,
name: 'bar',
categories: [
'Category002/sub-category001'
]
},
2: {
id: 2,
name: 'bazz',
categories: [
'Category001',
'Category002',
'Category003'
]
},
3: {
id: 3,
name: 'rem',
categories: [
'Category001/sub-category002/nth-category008',
'Category001/sub-category004',
'Category003/sub-category001'
]
}
}
DESIRED OUTPUT
{
0: {
"name": "Category001",
"isCategory": true,
"children": [
{
"id": 0,
"name": "foo",
"categoryPath": "Category001",
"isCategory": false
},
{
"id": 2,
"name": "bazz",
"categoryPath": "Category001",
"isCategory": false
},
{
"name": "sub-category004",
"categoryPath": "Category001/sub-category004",
"children": [
{
"id": 3,
"name": "rem",
"isCategory": false,
}
],
"isCategory": true
},
{
"name": "sub-category002",
"categoryPath": "Category001/sub-category002",
"children": [
{
"name": "sub-category008",
"categoryPath": "Category001/sub-category002/nth-category008",
"children": [
{
"id": 3,
"name": "rem",
"isCategory": false
}
],
"isCategory": true
},
],
"isCategory": true
},
{
"name": "sub-category002",
"categoryPath": "Category001/sub-category002",
"isCategory": true
}
],
"categoryPath": ""
},
1: {
"name": "Category002",
"isCategory": true,
"children": [
{
"id": 2,
"name": "bazz",
"categoryPath": "Category002",
"isCategory": false
},
{
"name": "sub-category001",
"categoryPath": "Category002/sub-category001",
"children": [
{
"id": 0,
"name": "foo",
"isCategory": false,
},
{
"id": 1,
"name": "bar",
"isCategory": false,
}
],
"isCategory": true
}
],
"categoryPath": ""
},
2: {
"name": "Category003",
"isCategory": true,
"children": [
{
"id": 2,
"name": "bazz",
"categoryPath": "Category002",
"isCategory": false
},
{
"name": "sub-category001",
"categoryPath": "Category003/sub-category001",
"children": [
{
"id": 0,
"name": "foo",
"isCategory": false,
}
],
"isCategory": true
}
],
"categoryPath": ""
}
}
Question
Is there an easy way of doing it in lodash?
A simple groupby won't do it though, LOL
var groups = _.chain(items)
.groupBy('categories')
.pairs()
.value();
Custom processing can not be avoided here in addition to lodash functions. The following is an attempt to use lodash at most:
var transformed = _(input)
.transform(function (result, item) {
_(item.categories)
.map(function (categoryPath) {
return categoryPath.split('/');
})
.each(function (categoryPathParts) {
var dict = result;
var par;
var fullpath = _.reduce(categoryPathParts, function (path, category, i) {
path += (i > 0 ? '/' : '') + category;
if (!(par = _.find(dict, 'name', category))) {
dict.push(par = {
name: category,
categoryPath: (i > 0 ? path : ''),
isCategory: true,
children: []
});
}
dict = _.find(dict, 'name', category).children;
return path;
}, "")
par.children.push({
id: item.id,
name: item.name,
isCategory: false,
categoryPath: fullpath,
});
}).value();
}, [])
.transform(function (resObj, resCat, i) {
resObj[i] = resCat;
}, {});
var input = {
0: {
id: 0,
name: 'foo',
categories: [
'Category001',
'Category002/sub-category001']
},
1: {
id: 1,
name: 'bar',
categories: [
'Category002/sub-category001']
},
2: {
id: 2,
name: 'bazz',
categories: [
'Category001',
'Category002',
'Category003']
},
3: {
id: 3,
name: 'rem',
categories: [
'Category001/sub-category002/nth-category008',
'Category001/sub-category004',
'Category003/sub-category001']
}
};
var transformed = _(input)
.transform(function (result, item) {
_(item.categories)
.map(function (categoryPath) {
return categoryPath.split('/');
})
.each(function (categoryPathParts) {
var dict = result;
var par;
var fullpath = _.reduce(categoryPathParts, function (path, category, i) {
path += (i > 0 ? '/' : '') + category;
if (!(par = _.find(dict, 'name', category))) {
dict.push(par = {
name: category,
categoryPath: (i > 0 ? path : ''),
isCategory: true,
children: []
});
}
dict = _.find(dict, 'name', category).children;
return path;
}, "")
par.children.push({
id: item.id,
name: item.name,
isCategory: false,
categoryPath: fullpath,
});
}).value();
}, [])
.transform(function (resObj, resCat, i) {
resObj[i] = resCat;
}, {});
document.getElementById('resultArea').textContent = JSON.stringify(transformed, null, 2);
textarea {
width: 100%;
}
<script src="http://cdnjs.cloudflare.com/ajax/libs/lodash.js/3.10.0/lodash.min.js"></script>
<textarea id="resultArea" rows="111" ></textarea>