array grouping conversion key start_section to end_section - javascript

Let's say I have below array :
[{id: 1, name: "header"},{id: 2, name: "start_section"},
{id: 3, name: "input"}, {id: 5, name: "image"},
{id: 6, name: "end_section"}, {id: 7, name: "header"},
{id: 8, name: "start_section"}, {id: 9, name: "input"},
{id: 10, name: "date"}, {id: 11, name: "end_section"},
]
I want this :
[{
id: 1,
name: "header"
}, {
id: 2,
name: "section",
child: [{
{
id: 3,
name: "input"
},
{
id: 5,
name: "image"
},
}],
}, {
id: 7,
name: "header"
}, {
id: 8,
name: "section",
child: [{
{
id: 9,
name: "input"
},
{
id: 10,
name: "date"
},
}]
}]
if I find start_section and end_section then it will form a new object , How do I change the array by grouping by the key specified in the example above in javascript?

If I get it right, you want something like this? It's simple approach with for loop and some flags:
const arr = [{id: 1, name: "header"},{id: 2, name: "start_section"},
{id: 3, name: "input"}, {id: 5, name: "image"},
{id: 6, name: "end_section"}, {id: 7, name: "header"},
{id: 8, name: "start_section"}, {id: 9, name: "input"},
{id: 10, name: "date"}, {id: 11, name: "end_section"},
];
// Set final array
let finalArray = [];
// Set sub object for groups (Childs)
let subObj = {};
// Flag for sub section stuff
let inSubSection = false;
// Loop array
for(let i = 0; i < arr.length; i++) {
if(arr[i].name === "end_section") {
// If we have end_section
// Set flag off
inSubSection = false;
// Push sub object to final array
finalArray.push(subObj);
} else if(arr[i].name === "start_section") {
// If we get start_section
// Set flag on
inSubSection = true;
// Set new sub object, set childs array in it
subObj = {
id: arr[i].id,
name: "section",
child: []
};
} else if(inSubSection) {
// If we have active flag (true)
// Push child to section array
subObj.child.push({
id: arr[i].id,
name: arr[i].name
});
} else {
// Everything else push straight to final array
finalArray.push(arr[i]);
}
}
// Log
console.log(finalArray);

you can Array.reduce function
let array = [{id: 1, name: "header"},{id: 2, name: "start_section"},
{id: 3, name: "input"}, {id: 5, name: "image"},
{id: 6, name: "end_section"}, {id: 7, name: "header"},
{id: 8, name: "start_section"}, {id: 9, name: "input"},
{id: 10, name: "date"}, {id: 11, name: "end_section"},
]
let outPut = array.reduce( (acc, cur, i, arr) => {
if (cur.name == "start_section") {
//find the end element
let endIndex = arr.slice(i).findIndex( e => e.name == "end_section") + i ;
//splice the child elements from base array
let child = arr.splice(i + 1, endIndex - 1 );
//remove last element that has "end_section"
child.splice(-1);
//append child
cur.child = child;
//sert the name as "section"
cur.name = "section";
}
//add to accumulator
acc.push(cur);
return acc;
}, []);
console.log(outPut);

Related

Get specific value from array object in a single line in typescript

I have a following array
const _array = [{id: 1, name: 'Adam'}, {id:3, name: 'Crystal'}, {id:2, name: 'Bob'}, {id: 4, name: 'Daisy'}];
How to write a single line of code in typescript to get item where name equal to Crystal from the array?
You can use array find method like following:
const _array = [
{ id: 1, name: "Adam" },
{ id: 3, name: "Crystal" },
{ id: 2, name: "Bob" },
{ id: 4, name: "Daisy" },
];
const item = _array.find((item) => item.name === "Crystal");
console.log(item);
Output
{ id: 3, name: 'Crystal' }

Efficient way of writing child of parents in javascript

var array = [
{id: 1, name: "Father", parent_id: null},
{id: 2, name: "Child", parent_id: 1},
{id: 3, name: "Child", parent_id: 1},
{id: 4, name: "ChildChild", parent_id: 2},
{id: 5, name: "ChildChildChild", parent_id: 4}
]
for(var i in array){
if(array[i].parent_id == null){
console.log(array[i].name);
} else {
for(var j in array){
if(array[i].parent_id == array[j].id && array[j].parent_id == null){
console.log(">" + array[i].name);
for(var x in array){
if(array[i].id == array[x].parent_id){
console.log(">>" + array[x].name);
}
}
}
}
}
}
Output:
Father
>Child
>>ChildChild
>Child
I have this array which has id, name and parent_id. Right now it is fixed but it could have multiple arrays and can be nested for n amount of times.
What I am doing here is iterating through each array and trying to find which are the parents and which one is the child.
I want to know if there is a more efficient way to write this code. For instance, I added a fifth id but that would require another for loop and so on. The output would be the same just a printed out tree.
You can use a Map to key your nodes by id, and then use recursion to traverse them in depth first order:
var array = [{id: 1, name: "Father", parent_id: null},{id: 2, name: "Child", parent_id: 1},{id: 3, name: "Child", parent_id: 1},{id: 4, name: "ChildChild", parent_id: 2},{id: 5, name: "ChildChildChild", parent_id: 4}];
let map = new Map(array.map(({id}) => [id, []])).set(null, []);
array.forEach(node => map.get(node.parent_id).push(node));
function dfs(nodes, indent="") {
for (let node of nodes) {
console.log(indent + node.name);
dfs(map.get(node.id), indent+">");
}
}
dfs(map.get(null));
You could create a tree and then make the output.
const
print = ({ name, children = [] }) => {
console.log(name)
children.forEach(print);
},
array = [{ id: 1, name: "Father", parent_id: null }, { id: 2, name: "Child", parent_id: 1 }, { id: 3, name: "Child", parent_id: 1 }, { id: 4, name: "ChildChild", parent_id: 2 }, { id: 5, name: "ChildChildChild", parent_id: 4 }],
tree = function (data, root) {
var t = {};
data.forEach(o => {
Object.assign(t[o.id] = t[o.id] || {}, o);
t[o.parent_id] = t[o.parent_id] || {};
t[o.parent_id].children = t[o.parent_id].children || [];
t[o.parent_id].children.push(t[o.id]);
});
return t[root].children;
}(array, null);
tree.forEach(print);
console.log(tree);
.as-console-wrapper { max-height: 100% !important; top: 0; }

Which is the best way to get an array difference from an object?

I have an array of values: ["1", "2", "3"] which contains essentially the reference of the records stored in this array of object:
[
{ id: 1, name: "John" },
{ id: 2, name: "Patrick" },
{ id: 3, name: "Jack" },
{ id: 4, name: "Paula" },
{ id: 5, name: "Sarah" }
]
I would like to return the missing reference from the array of objects, so the result will be: 4, 5. What I achieved so far is takes all the selected values of the first array from all the select available in the html:
var selected_options = $('.options-picker')
.map(function() { return this.value}).get();
this will return 1, 2, 3. How can I extract from the array of objects 4, 5?
Thanks in advance.
Use filter and includes to check the object ids against the values in the array.
const data = [
{ id: 1, name: "John" },
{ id: 2, name: "Patrick" },
{ id: 3, name: "Jack" },
{ id: 4, name: "Paula" },
{ id: 5, name: "Sarah" }
];
const items = [1, 2, 3];
const out = data.filter(obj => !items.includes(obj.id));
console.log(out);
This will do
var a=[
{ id: 1, name: "John" },
{ id: 2, name: "Patrick" },
{ id: 3, name: "Jack" },
{ id: 4, name: "Paula" },
{ id: 5, name: "Sarah" }
]
var b=['1', '2', '3'];
a.forEach((e)=>{
if(b.indexOf(e.id.toString())==-1)
{
b.push(e.id);
}
})
alert(b)

How to build a tree from a flat list in FP JS

I'm learning Functional Javascript and encounter into a problem.
I have this flat object:
const data = [
{id: 1, name: "Folder1", parentId: null},
{id: 2, name: "Folder2", parentId: null},
{id: 3, name: "Folder3", parentId: 1},
{id: 4, name: "Folder4", parentId: 2},
{id: 5, name: "Folder5", parentId: 3},
{id: 6, name: "Folder6", parentId: 3}
]
I desire to convert it to this hierarchical object, using only pure functions, no fors, ifs and other "imperative style statements".
Result should be:
[{
id: 1,
name: "Folder1",
parentId: null,
children = [{
id: 3,
name: "Folder3",
parentId: 1,
children = [{
id: 5,
name: "Folder5",
parentId: 3
},
{
id: 6,
name: "Folder6",
parentId: 3
}
]
}]
},
{
id: 2,
name: "Folder2",
parentId: null,
children = [{
id: 4,
name: "Folder4",
parentId: 2
}]
}
]
Any Ideas?
This is a proposal without if, but with Array#reduce and Map. It needs a sorted array.
var data = [{ id: 1, name: "Folder1", parentId: null }, { id: 2, name: "Folder2", parentId: null }, { id: 3, name: "Folder3", parentId: 1 }, { id: 4, name: "Folder4", parentId: 2 }, { id: 5, name: "Folder5", parentId: 3 }, { id: 6, name: "Folder6", parentId: 3 }],
tree = data
.reduce(
(m, a) => (
m
.get(a.parentId)
.push(Object.assign({}, a, { children: m.set(a.id, []).get(a.id) })),
m
),
new Map([[null, []]])
)
.get(null);
console.log(tree);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Or the same as above using ES2015 destructuring assignment. It needs a sorted array and also depends on the input data having only id, name and parentId keys.
var data = [{ id: 1, name: "Folder1", parentId: null }, { id: 2, name: "Folder2", parentId: null }, { id: 3, name: "Folder3", parentId: 1 }, { id: 4, name: "Folder4", parentId: 2 }, { id: 5, name: "Folder5", parentId: 3 }, { id: 6, name: "Folder6", parentId: 3 }],
tree = data
.reduce(
(m, {id, name, parentId}) => (
m
.get(parentId)
.push({id, name, parentId, children: m.set(id, []).get(id) }),
m
),
new Map([[null, []]])
)
.get(null);
console.log(tree);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Of course this should probably be written as a reusable function ...
var data = [{ id: 1, name: "Folder1", parentId: null }, { id: 2, name: "Folder2", parentId: null }, { id: 3, name: "Folder3", parentId: 1 }, { id: 4, name: "Folder4", parentId: 2 }, { id: 5, name: "Folder5", parentId: 3 }, { id: 6, name: "Folder6", parentId: 3 }];
// pure, reusable function
var buildTree = (data) =>
data.reduce(
(m, {id, name, parentId}) => (
m
.get(parentId)
.push({id, name, parentId, children: m.set(id, []).get(id) }),
m
),
new Map([[null, []]])
)
.get(null);
console.log(buildTree(data));
.as-console-wrapper { max-height: 100% !important; top: 0; }
Lastly, if the data is arriving in an unsorted order, we could handle sorting with a custom comparator
// unsorted data example
var data = [{ id: 6, name: "Folder6", parentId: 3 }, { id: 2, name: "Folder2", parentId: null }, { id: 3, name: "Folder3", parentId: 1 }, { id: 4, name: "Folder4", parentId: 2 }, { id: 5, name: "Folder5", parentId: 3 }, { id: 1, name: "Folder1", parentId: null }];
// immutable sort
var sort = (f,xs) => [...xs.sort(f)];
// custom tree comparator
var treeComparator = (x,y) =>
x.parentId - y.parentId || x.id - y.id;
// sort data, then reduce
var buildTree = (data) =>
sort(treeComparator, data).reduce(
(m, {id, name, parentId}) => (
m
.get(parentId)
.push({id, name, parentId, children: m.set(id, []).get(id) }),
m
),
new Map([[null, []]])
)
.get(null);
console.log(buildTree(data));
.as-console-wrapper { max-height: 100% !important; top: 0; }
You can do this with recursive function but you need to loop array with reduce and use if statements.
const arr = [
{id: 1, name: "Folder1", parentId: null},
{id: 2, name: "Folder2", parentId: null},
{id: 3, name: "Folder3", parentId: 1},
{id: 4, name: "Folder4", parentId: 2},
{id: 5, name: "Folder5", parentId: 3},
{id: 6, name: "Folder6", parentId: 3}
]
function buildTree(data, pId) {
return data.reduce(function(r, e) {
var e = Object.assign({}, e);
if (e.parentId == pId) {
var children = buildTree(data, e.id)
if (children.length) e.children = children
r.push(e)
}
return r;
}, [])
}
console.log(buildTree(arr, null))
const data = [
{id: 1, name: "Folder1", parentId: null},
{id: 2, name: "Folder2", parentId: null},
{id: 3, name: "Folder3", parentId: 1},
{id: 4, name: "Folder4", parentId: 2},
{id: 5, name: "Folder5", parentId: 3},
{id: 6, name: "Folder6", parentId: 3}
];
function trampoline ( f ) {
while ( f && f instanceof Function ) { f = f ( ); }
return f;
}
function buildTree ( data, copy, top = [] ) {
function recur ( data, copy, top ) {
copy = copy || data.concat ( [] );
let current = copy.shift ( );
current ? doWork ( ) : null;
function doWork ( ) {
top = top.concat ( ( ! current.parentId ? current : [] ) );
current.children = copy.filter ( x => { return current.id === x.parentId } );
}
return ( current ? recur.bind ( null, data, copy, top ) : top );
}
return trampoline ( recur.bind ( null, data, copy, top ) );
}
data.map ( x => { x [ 'children' ] = [ ]; return x; } );
console.log ( buildTree ( data ) );

How to remove objects from an array having values that are present in an other simple array (jquery)

I have the following two arrays:
SimpleArray = [2,3];
ObjectArray = [{
id: 1,
name: 'charles'
},{
id: 2,
name: 'john'
},{
id: 3,
name: 'allen'
},{
id: 4,
name: 'jack'
}];
I want to remove objects present in ObjectArray that have id's equal to the values present in SimpleArray.
If you want to delete data from original array then use Array#splice() method
SimpleArray = [2, 3];
ObjectArray = [{
id: 1,
name: 'charles'
}, {
id: 2,
name: 'john'
}, {
id: 3,
name: 'alen'
}, {
id: 4,
name: 'jack'
}];
for (var i = 0; i < ObjectArray.length; i++) {
if (SimpleArray.indexOf(ObjectArray[i].id) > -1) {
ObjectArray.splice(i, 1);
i--;
}
}
console.log(ObjectArray);
In case you need to generate new filtered array then use Array#filter() method
SimpleArray = [2, 3];
ObjectArray = [{
id: 1,
name: 'charles'
}, {
id: 2,
name: 'john'
}, {
id: 3,
name: 'alen'
}, {
id: 4,
name: 'jack'
}];
var res = ObjectArray.filter(function(v) {
return SimpleArray.indexOf(v.id) > -1
})
console.log(res);

Categories