Print array of objects entire path - javascript

Good Day People
I have an array of objects and I need to print out the path of each node value and last print key and value for special (by name) node.
This is the array of objects or JSON
[{
"Name": "2007",
"Elements": [{
"Name": "country1",
"Elements": [{
"House": "house1",
"water": 1.8
}],
"Data": {}
},
{
"Name": "country2",
"Elements": [{
"Name": "city2",
"Elements": [{
"Name": "neighbourhood2",
"Elements": [{
"House": "house2",
"water": 2.8
}]
}],
"Data": {}
}],
"Data": {}
},
{
"Name": "country3",
"Elements": [{
"House": "house2",
"uni bill": 3.8
}],
"Data": {}
}
],
"Data": {}
}]
The output should be like this
2007 > country1 > house > water: 1.8
2007 > city2 > neighbourhood2 > house2 > electricity: 2.8
2007 > country3 > house > uni bill: 3.8
++++++++++++++ edited +++++++++++++++
function objectToPaths(data) {
var validId = /^[a-z_$][a-z0-9_$]*$/i;
var result = [];
doIt(data, "");
return result;
function doIt(data, s) {
if (data && typeof data === "object") {
if (Array.isArray(data)) {
for (var i = 0; i < data.length; i++) {
doIt(data[i], s + "");
}
} else {
for (var p in data) {
if (validId.test(p)) {
doIt(data[p], s + " > " + data[p]);
} else {
doIt(data[p], s + "");
}
}
}
} else {
result.push(s);
}
}
}
this is a rewrite of a function I found here but I did not get the expected result
+++++++++++++++++++++++ end of the edit +++++++++++++++++++++++
Please help
Thanks in advance

What you are looking for is a Depth First Traversal function that recursively print properties:
function print(arr, path) { // print takes an array an an accumulated path from which it will start printing
arr.forEach(function(obj) { // for each object obj in the array
if(obj.Elements) { // if the object obj has sub elements in it
print(obj.Elements, path + " > " + obj.Name); // then call print on those elements, providin the absolute path to this object
} else { // otherwise (it is a leaf)
const bills = Object.keys(obj)
.filter(key => key !== "House")
.map(key => `${key}: ${obj[key]}`)
.join(', ')
console.log(path.slice(3) + " > " + obj.House + " > " + bills); // print the accumulated path along with the House property of this object (removing the first 3 letters from path which are equal to " > ")
}
});
};
var arr = [{"Name":"2007","Elements":[{"Name":"country1","Elements":[{"House":"house1","water":1.8}],"Data":{}},{"Name":"country2","Elements":[{"Name":"city2","Elements":[{"Name":"neighbourhood2","Elements":[{"House":"house2","water":2.8}]}],"Data":{}}],"Data":{}},{"Name":"country3","Elements":[{"House":"house2","uni bill":3.8}],"Data":{}}],"Data":{}}];
print(arr, "");

You could take a function for iterating and collect the path to the last object.
function iter(array, path) {
path = path || [];
array.forEach(function (o) {
if (o.Elements) {
return iter(o.Elements, path.concat(o.Name));
}
Object.keys(o).forEach(function (k) {
if (k !== 'House') {
console.log(path.concat(o.House, k).join(' > ') + ': ' + o[k]);
}
});
});
}
var data = [{ Name: "2007", Elements: [{ Name: "country1", Elements: [{ House: "house1", water: 1.8 }], Data: {} }, { Name: "country2", Elements: [{ Name: "city2", Elements: [{ Name: "neighbourhood2", Elements: [{ House: "house2", water: 2.8 }] }], Data: {} }], Data: {} }, { Name: "country3", Elements: [{ House: "house2", "uni bill": 3.8 }], Data: {} }], Data: {} }];
iter(data);
.as-console-wrapper { max-height: 100% !important; top: 0; }

Related

Flatten JSON objects in JavaScript

I have a JSON response and I need to flatten some objects according to conditions.
In my case, the condition is if object === "$"
I also need to flatten some array to string only. What is the best way to manage this? Any lib recommendations?
The final goal would be to use it as a GraphQL schema.
The JSON response is:
[
{
"$":{
"product_id":"110015888426488829026466000222",
"name":"Belstaff Trialmaster Pro W Motorradjacke Schwarz",
"sku_number":"B000134394",
"manufacturer_name":"BELSTAFF",
"part_number":"42050011L81N03379005436"
},
"discount":[
{
"$":{
"currency":"EUR"
},
"type":[
"amount"
]
}
],
"price":[
{
"$":{
"currency":"EUR"
},
"sale":[
"1195.00"
],
"retail":[
"1195.00"
]
}
],
"shipping":[
{
"cost":[
{
"$":{
"currency":"EUR"
},
"amount":[
"0.00"
],
"currency":[
"EUR"
]
}
],
"information":[
"3–7 Werktage"
],
"availability":[
"in-stock"
]
}
],
"attributeClass":[
{
"$":{
"class_id":"60"
},
"Product_Type":[
"Motorcycle"
],
"Size":[
"36,38,40,42,44,46,48"
],
"Material":[
"Waxed Leather"
],
"Color":[
"Schwarz"
],
"Gender":[
"Female"
],
"Age":[
"Adult"
]
}
]
},
...
]
And I want
[
{
"product_id":"110015888426488829026466000222",
"name":"Belstaff Trialmaster Pro W Motorradjacke Schwarz",
"sku_number":"B000134394",
"manufacturer_name":"BELSTAFF",
"part_number":"42050011L81N03379005436"
"discount":{
"currency":"EUR"
"type":"amount"
},
"price":{
"currency": "EUR",
"sale": "1195.00",
"retail": "1195.00"
},
"shipping":[
"cost":{
"currency": "EUR"
"amount": "0.00",
"currency": "EUR"
},
"information":"3–7 Werktage",
"availability": "in-stock"
],
"attributeClass":{
"class_id":"60",
"Product_Type": "Motorcycle",
"Size": "36,38,40,42,44,46,48",
"Material": "Waxed Leather",
"Color": "Schwarz",
"Gender": "Female",
"Age": "Adult"
}
},
...
]
What I tried:
const flatJson = async data => {
try {
const newData = await Promise.all(json.map( async (item, i) => {
xxx
}));
return newData
}
catch(err) {
console.log(err)
}
};
You could convert the various types to single objects.
const convert = object => {
if (!object || typeof object !== 'object') return object;
if (Array.isArray(object)) {
return object.every(v => typeof v === 'string')
? object.join()
: Object.assign({}, ...object.map(convert));
}
return Object.fromEntries(Object.entries(object).flatMap(([k, v]) =>
k === '$'
? Object.entries(v).map(([k, v]) => [k, convert(v)])
: [[k, convert(v)]]
));
};
var data = [{ $: { product_id: "110015888426488829026466000222", name: "Belstaff Trialmaster Pro W Motorradjacke Schwarz", sku_number: "B000134394", manufacturer_name: "BELSTAFF", part_number: "42050011L81N03379005436" }, discount: [{ $: { currency: "EUR" }, type: ["amount"] }], price: [{ $: { currency: "EUR" }, sale: ["1195.00"], retail: ["1195.00"] }], shipping: [{ cost: [{ $: { currency: "EUR" }, amount: ["0.00"], currency: ["EUR"] }], information: ["3–7 Werktage"], availability: ["in-stock"] }], attributeClass: [{ $: { class_id: "60" }, Product_Type: ["Motorcycle"], Size: ["36,38,40,42,44,46,48"], Material: ["Waxed Leather"], Color: ["Schwarz"], Gender: ["Female"], Age: ["Adult"] }] }],
result = data.map(convert);
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
You can try this recursion code
function recurseData(data, level) {
var newdata = {};
for(var prop in data) {
if( data[prop].constructor == Object && prop=="$") {
var data1 = recurseData(data[prop], level+1);
for(var prop1 in data1)
newdata[prop1] = data1[prop1];
}
else if(data[prop].constructor == Object){
newdata[prop] = recurseData(data[prop],level+1);
}
else if(data[prop].constructor == Array && level > 0 && data[prop][0].constructor != Object && data[prop].length==1){
newdata[prop] = data[prop][0];
}
else if(data[prop].constructor == Array) {
newdata[prop] = [];
for(var i=0;i<data[prop].length;i++)
newdata[prop].push( recurseData(data[prop][i],level+1) );
}
else if(prop!="$")
newdata[prop] = data[prop];
}
return newdata;
}
data[0] = recurseData(data[0], 0);
is simple loops through all tree structure and detects for a key $

How to replace all the values in JSON structure using javascript?

If I have JSON structure like this, I want to parse this JSON replace all values with '{param.keyName}', if the key value is array of objects than need to generate its value like {param.headKey[index]keyName}
{
"resources": [
{
"name": "prod",
"type": "local",
"properties": {
"zone": "asia",
"disks": [
{
"sizeGb": 3,
"diskType": "boot",
"name": "backup"
},
{
"sizeGb": 4,
"diskType": "ssd",
"name": "cache"
}
]
}
}
]
}
The output of the function should be JSON like this where all the values should be replaced with the mapping. If there is any array of objects than it should prefixed by array index like {param.disks0_name}, where disks is an array of objects.
{
"resources": [
{
"name": "prod",
"type": "local",
"properties": {
"zone": "{param.zone}",
"disks": [
{
"sizeGb": '{param.disks0_sizeGb}',
"diskType": '{param.disks0_diskType}',
"name": "{param.disks0_name}"
},
{
"sizeGb": '{param.disks1_zone}',
"diskType": '{param.disks1_diskType}',
"name": "{param.disks1_name}"
}
]
}
}
]
}
You could look for the arrays/objects and iterate them for getting the path for the last property.
Format as desired (which is unclear for nested arrays).
function formatPath(path) {
return `{${path.join('.')}}`;
}
function getPath(object, path = []) {
return Object.assign(
Array.isArray(object) ? [] : {},
...Object.entries(object).map(([k, v]) => ({
[k]: v && typeof v === 'object'
? getPath(v, path.concat(k))
: formatPath(path.concat(k))
}))
);
}
var data = { resources: [{ name: "prod", type: "local", properties: { zone: "asia", disks: [{ sizeGb: 3, diskType: "boot", name: "backup" }, { sizeGb: 4, diskType: "ssd", name: "cache" }] } }] };
data = { resources: data.resources.map(o => Object.assign({}, o, { properties: getPath(o.properties, ['param']) })) };
console.log(data);
.as-console-wrapper { max-height: 100% !important; top: 0; }
ES5
function formatPath(path) {
return '{' + path.join('.') + '}';
}
function getPath(object, path) {
path = path || [];
return Object.keys(object).reduce(
function (r, k) {
r[k] = object[k] && typeof object[k] === 'object'
? getPath(object[k], path.concat(k))
: formatPath(path.concat(k));
return r;
},
Array.isArray(object) ? [] : {}
);
}
var data = { resources: [{ name: "prod", type: "local", properties: { zone: "asia", disks: [{ sizeGb: 3, diskType: "boot", name: "backup" }, { sizeGb: 4, diskType: "ssd", name: "cache" }] } }] };
data = { resources: data.resources.map(function (o) {
return Object.keys(o).reduce(function (r, k) {
r[k] = k === 'properties'
? getPath(o.properties, ['param'])
: o[k];
return r;
}, {});
}) };
console.log(data);
.as-console-wrapper { max-height: 100% !important; top: 0; }

Traversing through JSON string to inner levels using recursive function using JavaScript

I have a JSON input which can go to any number of levels.
Here is the sample
var testJSON = [
{
'name':'USER1',
'id':1,
'child':[],
},{
'name':'USER2',
'id':2,
'child':[{
'name':'USER2_CHILD1',
'id':21,
'child':[]
},{
'name':'USER2_CHILD2',
'id':22,
'child':[{
'name':'USER2_CHILD2_CHILD1',
'id':221,
'child':[]
}]
}],
},{
'name':'USER3',
'id':3,
'child':[{
'name':'USER3_CHILD1',
'id':31,
'child':[]
}],
}];
I want to add a JSON data in child array by finding matching id using the recursive function. For example, if want to add JSON object at id==1; then it was possible by using for loop but what if I want to add JSON object at id==22 or id==221.
I am trying using below code
var body = '';
function scan(obj)
{
var k;
if (obj instanceof Object) {
for (k in obj){
if (obj.hasOwnProperty(k)){
body += 'scanning property ' + k + '<br/>';
scan( obj[k] );
}
}
} else {
body += 'found value : ' + obj + '<br/>';
};
};
scan(testJSON);
document.getElementById('output').innerHTML = body;
You could use an iteration with a check and return the object, if found.
function getObject(array, id) {
var object;
array.some(o => object = o.id === id && o || getObject(o.child || [], id));
return object;
}
var data = [{ name: "USER1", id: 1, child: [] }, { name: "USER2", id: 2, child: [{ name: "USER2_CHILD1", id: 21, child: [] }, { name: "USER2_CHILD2", id: 22, child: [{ name: "USER2_CHILD2_CHILD1", id: 221, child: [] }] }] }, { name: "USER3", id: 3, child: [{ name: "USER3_CHILD1", id: 31, child: [] }] }];
console.log(getObject(data, 1));
console.log(getObject(data, 21));
console.log(getObject(data, 221));
Try this function, you need to parse JSON before
function insertRecord(id,dataToInsert,jsonInput){
let checkIndex = function (arrayElement){
return arrayElement.id === id;
}
let index = jsonInput.findIndex(checkIndex);
if(index != -1) {
if(jsonInput[index].child) {
jsonInput[index].child.push(dataToInsert);
}
else {
jsonInput[index].child = [dataToInsert];
}
}
else {
jsonInput.forEach(function(arrEle, eleIndex){
if(arrEle.child) {
insertRecord(id,dataToInsert,arrEle.child);
}
});
}
}
insertRecord(22,{
'name':'USER1',
'id':33,
'child':[],
},testJSON);

make combinations of two array in json

Input :
"options": [
{
"name": "Color",
"values": [
"Blue",
"Black"
]
},
{
"name": "Size",
"values": [
"Small",
"Large"
]
}
]
Output: "variants": [
{
"option1": "Blue",
"option2": "Small"
},
{
"option1": "Blue",
"option2": "Large"
},
{
"option1": "Black",
"option2": "Small"
},
{
"option1": "Black",
"option2": "Large"
}
]
How to solve this using recursion ?The options array can contain multiple name and i need the above out to be displayed. Can it be done using cartesian product i guess
You could take an iterative and recursive approach for getting all option combinations.
function getCombinations(array) {
function iter(i, temp) {
if (i === array.length) {
result.push(temp.reduce(function (o, v, i) {
o['option' + (i + 1)] = v;
return o;
}, {}));
return;
}
array[i].values.forEach(function (a) {
iter(i + 1, temp.concat(a));
});
}
var result = [];
iter(0, []);
return result;
}
var options = [{ name: "Color", values: ["Blue", "Black"] }, { name: "Size", values: ["155", "159"] }, { name: 'Material', values: ['Sand', 'Clay', 'Mud'] }],
variants = getCombinations(options);
console.log(variants);
.as-console-wrapper { max-height: 100% !important; top: 0; }
ES6
function getCombinations(array) {
function iter(i, temp) {
if (i === array.length) {
result.push(temp);
return;
}
array[i].values.forEach(a => iter(i + 1, Object.assign({}, temp, { ['option' + (i + 1)]: a })));
}
var result = [];
iter(0, {});
return result;
}
var options = [{ name: "Color", values: ["Blue", "Black"] }, { name: "Size", values: ["155", "159"] }, { name: 'Material', values: ['Sand', 'Clay', 'Mud'] }],
variants = getCombinations(options);
console.log(variants);
.as-console-wrapper { max-height: 100% !important; top: 0; }
You can use nested Array.map() calls, create the objects, and flatten the sub arrays using Array.concat():
const options = [{"name":"Color","values":["Blue","Black"]},{"name":"Size","values":["155","159"]}]
const [{ values: colors }, { values: sizes }] = options
const result = [].concat(...colors.map((option1) => sizes.map((option2) => ({
option1,
option2
}))))
console.log(result)
var myarray = {"options": [
{
"name": "Color",
"values": [
"Blue",
"Black"
]
},
{
"name": "Size",
"values": [
"155",
"159"
]
}
]};
const key = myarray.options[0].values;
const value =myarray.options[1].values;
const output = _.zipWith(key, value, (key, value)=> ({ key, value }));
console.log(output);
<script src="https://cdn.jsdelivr.net/lodash/4.16.6/lodash.min.js"></script>

Ignoring "The" when sorting an object array

I have an array:
var array = {
"mylist": [
{
"item1": "The Ba",
"id": 1
},
{
"item1": "Hurts Ama",
"id": 2
}
]
}
and to sort them I am using the following function:
function sortByItem(a,b) {
if (a.item1 < b.item1)
return -1;
if (a.item1 > b.item1)
return 1;
return 0;
}
which gives me the output
[Hurts Ama, The Ba]
However, I don't want "The" to be included when comparing, so that the output would actually be:
[Ba, Hurts Ama]
You could replace the at the beginning with following whitespace.
var array = [{ item1: "The Ba", id: 1 }, { item1: "Hurts Ama", id: 2 }, { item1: "Thereafter ", id: 3 }];
array.sort(function (a, b) {
function getStripped(s) { return s.replace(/^the\s+/i, ''); }
return getStripped(a.item1).localeCompare(getStripped(b.item1));
});
console.log(array)
.as-console-wrapper { max-height: 100% !important; top: 0; }
first map a transform function every of your objects that removes any "The " then run your sort by
function transform(item) {
return {
id: item.id,
item: item.replace("The ","")
}
}
var list =
[
{
"item": "The Ba",
"id": 1
},
{
"item": "Hurts Ama",
"id": 2
}
]
list.map(transform).sort(sortByItem)

Categories

Resources