How to transform this specific js array into js object? - javascript

I have one javascript array got from back end api, for convenience, need to be sort into the form of below, described as final target.
But I don't know how to start. Anyone can help?
The original src array is like below :
var src = [
{
"parent_kind" : "Animal",
"name" : "Cow"
},
{
"name" : "Animal"
},
{
"parent_kind" : "Animal",
"name" : "Dog"
},
{
"parent_kind" : "Animal",
"name" : "Horse"
},
{
"name" : "Vehicle"
},
{
"parent_kind" : "Vehicle",
"name" : "Bus"
},
{
"parent_kind" : "Bus",
"name" : "Shuttle"
},
]
The final target is :
{
"Vehicle" : {
"Bus" : {
"Shuttle" : {}
}
},
"Animal" : {
"Cow" : {},
"Dog" : {},
"Horse" : {}
}
}
I can got each element of the original array by
for (let ele of src) {
console.log(ele)
}

you can do that with a simple Array.reduce() method
var src =
[ { parent_kind: 'Animal', name: 'Cow' }
, { name: 'Animal' }
, { parent_kind: 'Animal', name: 'Dog' }
, { parent_kind: 'Animal', name: 'Horse' }
, { name: 'Vehicle' }
, { parent_kind: 'Vehicle', name: 'Bus' }
, { parent_kind: 'Bus', name: 'Shuttle' }
]
let res = src.reduce((a,{parent_kind,name},i)=>
{
if(!!parent_kind)
{
let np = a.p.find(x=>x.pN===parent_kind)
if(!np)
{
a.r[parent_kind] = {}
np = {pN:parent_kind, e:a.r[parent_kind]}
a.p.push( np )
}
let z = np.e[name] = {}
a.p.push( {pN:name, e:z} )
}
return (i===a.len)? a.r : a
}
,{len:src.length-1,r:{},p:[]})
console.log( res )
.as-console-wrapper { max-height: 100% !important; top: 0; }

if you can ok with loop the src many times :-( That's performance is not a concern.
var src = [{
"parent_kind": "Animal",
"name": "Cow"
},
{
"name": "Animal"
},
{
"parent_kind": "Animal",
"name": "Dog"
},
{
"parent_kind": "Animal",
"name": "Horse"
},
{
"name": "Vehicle"
},
{
"parent_kind": "Vehicle",
"name": "Bus"
},
{
"parent_kind": "Bus",
"name": "Shuttle"
},
];
const fn = (source, result, parent) => {
const children = source.filter(({
parent_kind
}) => parent_kind === parent).map(({
name
}) => name);
children.forEach(c => result[c] = {});
children.forEach(c => fn(source, result[c], c));
}
result = {};
fn(src, result)
console.log(result);

Related

I want to compare inner array in JSON array of object and return new array depending on condition using JavaScript

I have following array of object
let studentArray =
[{
"name" : "Computer Science",
"students" : [
{
"student_name" : "A"
},
{
"student_name" : "B"
}
]
},
{
"name" : "Math",
"students" : [
{
"student_name" : "A"
},
{
"student_name" : "B"
},
{
"student_name" : "C"
}
]
}]
and I want answer like below.
[
{
"student_name" : "A",
"courses": ["Computer Science", "Math"]
},
{
"student_name" : "B",
"courses": ["Computer Science", "Math"]
},
{
"student_name" : "C",
"courses": ["Math"]
}
]
Please help with javascript functionality and according to data structure algorithm.
I have tried below it is not working.
I there any another way to doing this Using different another loops or something another logic for that.
let studentArray = [{
"name": "Computer Science",
"students": [{
"student_name": "A"
},
{
"student_name": "B"
}
]
},
{
"name": "Math",
"students": [{
"student_name": "A"
},
{
"student_name": "B"
},
{
"student_name": "C"
}
]
}
]
studentArray.forEach((item, index) => {
//console.log(item);
if (index > 0) {
console.log("Previous: " + studentArray[index - 1].students);
}
if (index < studentArray.length - 1) {
console.log("Next: " + studentArray[index + 1].students);
}
//console.log(studentArray);
console.log(item.students.filter(comparer(item.students)));
});
function comparer(otherArray) {
return function(current) {
return otherArray.filter(function(other) {
return other.value == current.value && other.display == current.display
}).length == 0;
}
}
You can use Array.reduce() on the studentArray to group students with their courses.
We create an object keyed by student name and iterate over each course's student array to add students to the map (using for...each).
Finally, we use Object.values() to turn our map into an array:
const studentArray = [{ "name" : "Computer Science", "students" : [ { "student_name" : "A" }, { "student_name" : "B" } ] }, { "name" : "Math", "students" : [ { "student_name" : "A" }, { "student_name" : "B" }, { "student_name" : "C" } ] }];
const result = Object.values(studentArray.reduce((acc, course) => {
for(let student of course.students) {
let student_name = student.student_name;
acc[student_name ] = acc[student_name ] || { student_name , courses: []};
acc[student_name ].courses.push(course.name);
}
return acc;
}, {}))
console.log(result)
Use a nested forEach loop
const studentArray = [{
name: "Computer Science",
students: [{
student_name: "A"
},
{
student_name: "B"
}
]
},
{
name: "Math",
students: [{
student_name: "A"
},
{
student_name: "B"
},
{
student_name: "C"
}
]
}
];
const newArr = [];
studentArray.forEach((c) => {
c.students.forEach((s) => {
let studentIndex = newArr.findIndex(el => el.student_name === s.student_name);
studentIndex === -1 ? newArr.push({
student_name: s.student_name,
courses: [c.name]
}) : newArr[studentIndex].courses.push(c.name)
})
})
console.log(newArr);
Another approach using reduce, map, and some ES6 spread syntax:
const courses = [
{
"name" : "Computer Science",
"students" : [{ "student_name" : "A" }, { "student_name" : "B" }]
},
{
"name" : "Math",
"students" : [{ "student_name" : "A" }, { "student_name" : "B" }, { "student_name" : "C" }]
}
]
// Add students from a course to an array if they're not present already
const selectUniqueStudents = (currentStudentList, course) =>
currentStudentList.concat(course.students.filter(newStudent =>
currentStudentList.every(
currentStudent => currentStudent.student_name !== newStudent.student_name
)
))
// Add each course that the student is on to an array and append to the
// student object
const addCourseDetails = (student) => ({
...student,
courses: courses
.filter(course =>
course.students.some(courseStudent => courseStudent.student_name === student.student_name)
)
.map(course => course.name)
})
const transformedResult = courses
.reduce(selectUniqueStudents, [])
.map(addCourseDetails)
console.log(transformedResult)
// Returns:
//
// [
// { student_name: 'A', courses: [ 'Computer Science', 'Math' ] },
// { student_name: 'B', courses: [ 'Computer Science', 'Math' ] },
// { student_name: 'C', courses: [ 'Math' ] }
// ]
Same as with Vineet's answer, Terry's would run faster. This is not as concise or easy to read either. But the demonstration of aggregate array functions and ES6 syntax might be useful.

How in JS to merge in one object two json objects where the ID of on object correspond on the same ID of the second object

My question relates to the fact I'm querying 2 different objects from DB and the result is in JSON. I need to merge them into one.
The 2 objects have in common this two key/value IRBId = ... and id = ... and they look as an example
OBJ 1
{
"data":{
"IRBs":{
"nodes":[
{
"id":"8",
"name":"Admin ",
},
{
"id":"9",
"name":"Again",
}
],
}
}
}
OBJ 2
{
"data":{
"informedConsentForms":{
"count":3,
"nodes":[
{
"id":"93",
...
"IRBId":"9",
},
{
"id":"92",
...
"IRBId":"8",
},
{
"id":"91",
...
"IRBId":"8",
}
],
}
},
As you will see above OBJ 2 and OBJ 1 corresponding with the same at IRBid and id.
What I need is to merge the two OBJ where IRBId OBJ 2 === id OBJ 1
The result I would expect after the merge is
OBJ merged
{
[{
"id":"93",
...
"IRBId":"9",
"irb": {
"name":"Again ",
...
}
},
{
"id":"92",
...
"IRBId":"8",
"irb": {
"name":"Admin ",
...
}
},
{
"id":"91",
...
"IRBId":"8",
"irb": {
"name":"Admin ",
...
}
],
},
I don't know how to make it looks like this.
Try using Array.reduce
Logic
Loop through second object data nodes
Find the matching nodes from object 1 data nodes.
Push to accumulator with required details. (I have added only the nodes that was mentioned in in Expected resut, you can add asmuch as you need.)
const obj1 = {
"data": {
"IRBs": {
"nodes": [
{
"id": "8",
"name": "Admin ",
},
{
"id": "9",
"name": "Again",
}
],
}
}
}
const obj2 = {
"data": {
"informedConsentForms": {
"count": 3,
"nodes": [
{
"id": "93",
"IRBId": "9",
},
{
"id": "92",
"IRBId": "8",
},
{
"id": "91",
"IRBId": "8",
}
],
}
},
};
const obj1List = obj1.data.IRBs.nodes;
const output = obj2.data.informedConsentForms.nodes.reduce((acc, curr) => {
const matchingNode = obj1List.find((item) => item.id === curr.IRBId);
if (matchingNode) {
acc.push({
id: curr.id,
IRBId: curr.IRBId,
irb: {
name: matchingNode.name
}
})
}
return acc;
}, []);
console.log(output);
You need to use the map function on the nodes in the first object to construct a new object that contains the second and first object's attributes.
const obj1 = {
"data": {
"IRBs": {
"nodes": [{
"id": "8",
"obj1": "one",
"name": "Admin ",
},
{
"id": "9",
"obj1": "two",
"name": "Again",
}
]
}
}
};
const obj2 = {
"data": {
"informedConsentForms": {
"count": 3,
"nodes": [{
"id": "93",
"obj2": "1",
"IRBId": "9",
},
{
"id": "92",
"obj2": "2",
"IRBId": "8",
},
{
"id": "91",
"obj2": "3",
"IRBId": "8",
}
],
}
}
};
const obj1Data = obj1.data.IRBs.nodes;
const obj2Data = obj2.data.informedConsentForms.nodes;
const res = obj2Data.map(item => {
const obj1Item = obj1Data.find(obj1Item => item.IRBId === obj1Item.id);
return obj1Item ? { ...item, "irb": { ...obj1Item}} : { ...item};
});
console.log(res);
i am using nested loop, try this one
const obj2 = {
"data":{
"informedConsentForms":{
"count":3,
"nodes":[
{
"id":"93",
"IRBId":"9",
},
{
"id":"92",
"IRBId":"8",
},
{
"id":"91",
"IRBId":"8",
}
],
}
},
}
const obj1 = {
"data":{
"IRBs":{
"nodes":[
{
"id":"8",
"name":"Admin ",
},
{
"id":"9",
"name":"Again",
}
],
}
}
}
const result = [];
const obj2Nodes = obj2.data.informedConsentForms.nodes;
for(let i = 0; i < obj2Nodes.length; i++) {
const obj1Nodes = obj1.data.IRBs.nodes
for(let j = 0; j < obj1Nodes.length; j++) {
if(obj2Nodes[i].IRBId === obj1Nodes[j].id) {
const {id, ...reObj1Nodes} = obj1Nodes[j];
result.push({
...obj2Nodes[i],
'irb': {
...reObj1Nodes
}
})
}
}
}
console.log(result)

Getting empty data while trying to get desired format of object

I have an object
"data" : [
{
"name" : "Heading",
"text" : "Text Heading",
"type" : "string",
"values" : [
"Arthur"
]
},
{
"name" : "Source",
"text" : "Source Reference",
"type" : "string",
"values" : [
"Jhon"
]
},
{
"name" : "Place",
"text" : "Bank Building",
"type" : "string",
"values" : [
"Mark"
]
},
{
"name" : "Animal",
"text" : "Branch",
"type" : "string",
"values" : [
"Susan"
]
}
]
there is a function i am passing the object and an array as the arguments
fieldArray=["Heading", "Animal"]
myFunction(fieldArray, data){
... your code here
}
I need to get the output in the below format where I have to search the object with the fields in myArray with the name key of data. Then I need to put the value of the searched object in the below format
[{
"id": 1,
"cells": [{
"id": "ConstId",
"cellContent": "Heading"
},
{
"id": "ConstValue",
"cellContent": "Arthur"
}
]
},
{
"id": 2,
"cells": [{
"id": "ConstId",
"cellContent": "Animal"
},
{
"id": "ConstValue", //a constant field name as ConstValue
"cellContent": "Susan" // the value of the second field in the myArray from object with name Animal
}
]
}
]
I have tried this
const getFormattedData = (fieldArray: any, data: any) => {
let innerData: any = [];
for (let i=0; i<fieldArray.length; i++){
const indexNumber = data.find((key: any) => key.name === fieldArray[i])
if(indexNumber != undefined){
innerData.push({
id: i+1,
cells:[{
id: 'inquiryName',
cellContent: indexNumber.name
},
{
id: 'value',
cellContent: indexNumber.values.toString()
}
]
})
}
console.log('innerData :>> ', innerData);
}
}
You could use the below. Since you tagged javascript, posting answer in JS.
function formatData(data, fieldArray) {
let ret = [];
fieldArray.forEach((field, i) => {
let dataObj = data.filter(d => d.name === field)[0]
if( dataObj ) {
ret.push({
"id": 1,
"cells": [{
"id": "ConstId",
"cellContent": field
},
{
"id": "ConstValue",
"cellContent": dataObj.values[0] //Put whole obj or just first
}
]
})
}
})
return ret;
}
Link to plnkr

manipulate two array of objects make new array and update the attribute of object1 and add in the new array

Hi I am trying to compare two array of objects and want to achieve the custom array of object by manipulating it.
I would like to achieve something like this by checking each time anything from object1 is removed or not? if it is removed then it should change attribute to 'Y'.
object 1 = [
{
"label":"a",
"removed":"N",
"value":1
},
{
"label":"b",
"removed":"N",
"value":2
}
]
object 2 =[
{
"label":"a",
"removed":"N",
"value":1
},
{
"label":"c",
"removed":"N",
"value":3
}
]
result should be =
[{
label:"a",
removed:"N",
value:1
},{
label:"b",
removed:"Y",
value:2
},{
label:"c",
removed:"N",
value:3
}]
I have tried to loop both array and tried to achieve the same but it is somehow not working.
I tried following code.
let data = []
object1.forEach((item1) => {
object2.forEach((item2) => {
if (item1.value === item2.value) {
data.push(Object.assign(item1));
} else {
item2.removeFlag = 'Y';
data.push(Object.assign(item1, item2));
}
}
}
...Updated Question.....
obj1 = [
{
"val":"type1",
"removed":"N",
"data":[
{
"label":"type1-a",
"removed":"N",
"dataid":16
},
{
"label":"type1-b",
"removed":"N",
"dataid":26
}
]
},
{
"val":"type2",
"removed":"N",
"data":[
{
"label":"type2-a",
"removed":"N",
"dataid":12
},
{
"label":"type2-b",
"removed":"N",
"dataid":34
}
]
},
{
"val":"type3",
"removed":"N",
"id":124,
"label":"type3-label1"
},
{
"val":"type4",
"removed":"N",
"id":126,
"label":"type4-label1"
},
{
"val":"type4",
"removed":"N",
"id":128,
"label":"type4-label2"
}
]
obj2 = [
{
"val":"type1",
"removed":"N",
"data":[
{
"label":"type1-a",
"removed":"N",
"dataid":16
},
{
"label":"type1-c",
"removed":null,
"dataid":null
},
{
"label":"type1-d",
"removed":null,
"dataid":null
}
]
},
{
"val":"type3",
"removed":"N",
"id":124,
"label":"type3-label1"
},
{
"val":"type4",
"removed":"N",
"id":126,
"label":"type4-label1"
},
{
"val":"type4",
"removed":null,
"id":null,
"label":"type4-label3"
}
]
result = [
{
"val":"type1",
"removed":"N",
"data":[
{
"label":"type1-a",
"removed":"N",
"dataid":16
},
{
"label":"type1-b",
"removed":"Y",
"dataid":26
},
{
"label":"type1-c",
"removed":null,
"dataid":null
},
{
"label":"type1-d",
"removed":null,
"dataid":null
}
]
},
{
"val":"type2",
"removed":"Y",
"data":[
{
"label":"type2-a",
"removed":"N",
"dataid":12
},
{
"label":"type2-b",
"removed":"N",
"dataid":34
}
]
},
{
"val":"type3",
"removed":"N",
"id":124,
"label":"type3-label1"
},
{
"val":"type4",
"removed":"N",
"id":126,
"label":"type4-label1"
},
{
"val":"type4",
"removed":"Y",
"id":128,
"label":"type4-label2"
},
{
"val":"type4",
"removed":null,
"id":null,
"label":"type4-label3"
}
]
const object1 = [{
"label": "a",
"removed": "N",
"value": 1
},
{
"label": "b",
"removed": "N",
"value": 2
}
]
const object2 = [{
"label": "a",
"removed": "N",
"value": 1
},
{
"label": "c",
"removed": "N",
"value": 3
}
]
const result = [...object2.map(record => {
const record2 = object1.find(pr => pr.label === record.label) || {};
return {
...record,
...record2
}
}), ...object1.filter(pr => !object2.some(npr => npr.label === pr.label)).map(pr => ({ ...pr,
removed: "Y"
}))]
console.log(result);
--Edit
With nested data you have to repeat the same code inside reduce function.
Example
const result = [...object2.map(record => {
const record2 = object1.find(pr => pr.val === record.val) || {};
const data = [...(record.data || []).map(pr => ({ ...pr,
...(record2.data.find(npr => npr.label === pr.label) || {})
})),
...(record2.data || []).filter(pr => !record.data.some(npr => npr.label === pr.label)).map(pr => ({ ...pr,
removed: 'Y'
}))
]
return {
...record,
...record2,
data
}
}), ...object1.filter(pr => !object2.some(npr => npr.val === pr.val)).map(pr => ({ ...pr,
removed: "Y"
}))]

Javascript Nested JSON Parsing

I have a json object that object contains main nodes and nested nodes. Each node have a property "type", i want to remove the nodes object which contains the property "type = doc".Please find below example json image format. I attached 2 files one image is the input format and other one is the output format.
var json = {
"navigations": [
{
"disp_order": "1",
"menu_id": "25266",
"nodes": [
{
"disp_order": "2",
"menu_id": "18951",
"type": "DOC"
}
],
"type": "MENU"
},
{
"disp_order": "20",
"menu_id": "25204",
"nodes": [
{
"disp_order": "1",
"menu_id": "10295",
"type": "DOC"
},
{
"disp_order": "10",
"menu_id": "25207",
"nodes": [
{
"disp_order": "999",
"menu_id": "17250",
"type": "DOC"
},
],
"type": "MENU"
},
{
"disp_order": "20",
"menu_id": "25209",
"nodes": [
{
"disp_order": "999",
"menu_id": "18881",
"type": "DOC"
},
],
"type": "MENU"
},
],
"type": "MENU"
},
]
}
https://jsfiddle.net/1hoctvdp/
function deleteNonMenu(obj) {
if (obj.type == "DOC") {
return true;
}
if (obj.nodes) {
for (var i = 0; i < obj.nodes.length; i++) {
var res = deleteNonMenu(obj.nodes[i]);
if (res == true) {
delete obj.nodes[i];
}
}
}
return false;
}
for (var i = 0; i < json.navigations.length; i++) {
var result = deleteNonMenu(json.navigations[i]);
if (result == true) {
delete json.navigations[i];
}
}
console.log(json);
Just as an alternative, you could use this ES6 function, which leaves the original object immutable, and creates the filtered version as return value:
function withoutDocNodes(obj) {
return Object(obj) !== obj ? obj // Primitive value: return w/o change
: Object.assign(Array.isArray(obj) ? [] : {}, // Create array or object
// With following properties:
...Object.keys(obj) // For each property:
// Exclude those with DOC type in their value
.filter( key => Object(obj[key]).type !== 'DOC')
// Get recursive value (also without DOC types)
.map( key => [withoutDocNodes(obj[key]), key] )
// Exclude if resulting value is an empty (object or array)
.filter ( ([o]) => Object.keys(o).length )
// Produce key/value to add: arrays get index as property
.map( ([o, key], i) => ({ [Array.isArray(obj) ? i : key]: o }) )
);
}
const obj = {
"navigations": [
{
"disp_order": "1",
"menu_id": "25266",
"nodes": [
{
"disp_order": "2",
"menu_id": "18951",
"type": "DOC"
}
],
"type": "MENU"
},
{
"disp_order": "20",
"menu_id": "25204",
"nodes": [
{
"disp_order": "1",
"menu_id": "10295",
"type": "DOC"
},
{
"disp_order": "10",
"menu_id": "25207",
"nodes": [
{
"disp_order": "999",
"menu_id": "17250",
"type": "DOC"
},
],
"type": "MENU"
},
{
"disp_order": "20",
"menu_id": "25209",
"nodes": [
{
"disp_order": "999",
"menu_id": "18881",
"type": "DOC"
},
],
"type": "MENU"
},
],
"type": "MENU"
},
]
};
const result = withoutDocNodes(obj);
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
This one is also working, try this code :
function mainFunction() {
var data = new Array();
data = excludeDocs(json.navigations);
}
function excludeDocs(nodes) {
var _docs = new Array();
$.each(nodes, function(index, node) {
if(typeof node === 'object') {
if(node.type === 'DOC') {
_docs.push(node.menu_id);
}
else if(typeof node.nodes === 'object') {
var _nodes = excludeDocs(node.nodes);
if(!(typeof nodes === 'object' && nodes.length > 0)) {
delete node.nodes;
}
else {
node.nodes = _nodes;
}
}
}
});
return nodes.filter(function(n) {
return !_docs.includes(n.menu_id);
});
}
Here is a solution using object-scan. It's powerful for data processing once you wrap your head around it.
Note: (1) Expects well behaved input and (2) modifies the input in place
// const objectScan = require('object-scan');
const prune = (type, input) => {
objectScan(['**.nodes[*].type'], {
filterFn: ({ value, gparent, gproperty }) => {
if (value === type) {
gparent.splice(gproperty, 1);
}
}
})(input);
};
const json = { navigations: [{ disp_order: '1', menu_id: '25266', nodes: [{ disp_order: '2', menu_id: '18951', type: 'DOC' }], type: 'MENU' }, { disp_order: '20', menu_id: '25204', nodes: [{ disp_order: '1', menu_id: '10295', type: 'DOC' }, { disp_order: '10', menu_id: '25207', nodes: [{ disp_order: '999', menu_id: '17250', type: 'DOC' }], type: 'MENU' }, { disp_order: '20', menu_id: '25209', nodes: [{ disp_order: '999', menu_id: '18881', type: 'DOC' }], type: 'MENU' }], type: 'MENU' }] };
prune('DOC', json);
console.log(json);
// => { navigations: [ { disp_order: '1', menu_id: '25266', nodes: [], type: 'MENU' }, { disp_order: '20', menu_id: '25204', nodes: [ { disp_order: '10', menu_id: '25207', nodes: [], type: 'MENU' }, { disp_order: '20', menu_id: '25209', nodes: [], type: 'MENU' } ], type: 'MENU' } ] }
.as-console-wrapper {max-height: 100% !important; top: 0}
<script src="https://bundle.run/object-scan#16.0.0"></script>
Disclaimer: I'm the author of object-scan

Categories

Resources