Javascript Recursion with helper function - javascript

I have this chunk of code and I want to print this out.
a
|->b
|->c
|->e
It works when I use
let spaceStr = " ".repeat(level) + "|->";
but not when I use the helper function getSpace.
It only prints the following:
a
|->b
I cannot figure out why. Can someone explain to me?
const obj =
{ name: 'a', children:
[ { name: 'b', children: [] }
, { name: 'c', children:
[ { name: 'e', children: [] }
]
}
]
}
function getSpace(level){
var str = '';
for (i=0; i < level; i++){
str += ' ';
}
str += '|->';
return str
}
function getPath(obj, level) {
let result = [];
let resultString = '';
let spaceStr = " ".repeat(level) + "|->";
// let spaceStr = getSpace(level);
if (obj.children.length === 0) {
return spaceStr+obj.name;
} else {
if (level === 0) {
result.push(obj.name);
} else {
result.push(spaceStr + obj.name);
}
for (i=0;i<obj.children.length;i++){
result.push(getPath(obj.children[i], level+1));
}
}
return result;
}
function printPath(result){
for (i=0;i<result.length;i++){
console.log(result[i]);
}
return
}
printPath(getPath(obj,0).flat());

By using i=0 in your loops, you're not scoping the variable i correctly to the loop. Instead, it will bubble up to the closest instance of that variable name (until it hits the global scope). Consider using let i = 0 in your loops to properly scope the variable. See the following functioning code:
const obj = {
"name": "a",
"children": [{
"name": "b",
"children": []
},
{
"name": "c",
"children": [{
"name": "e",
"children": []
}]
}
]
}
function getSpace(level){
var str = '';
for (let i = 0; i < level; i++){
str += ' ';
}
str += '|->';
return str
}
function getPath(obj, level) {
let result = [];
let resultString = '';
//let spaceStr = " ".repeat(level) + "|->";
let spaceStr = getSpace(level);
if (obj.children.length === 0) {
return spaceStr+obj.name;
} else {
if (level === 0) {
result.push(obj.name);
} else {
result.push(spaceStr + obj.name);
}
for (let i = 0;i<obj.children.length;i++){
result.push(getPath(obj.children[i], level+1));
}
}
return result;
}
function printPath(result){
for (let i = 0;i<result.length;i++){
console.log(result[i]);
}
return
}
printPath(getPath(obj,0).flat());

Related

Convert plain text to deeply json object using JavaScript

I have one plain string including some conditions like this.
const optionString = '{2109} AND ({2370} OR {1701} OR {2702}) AND {1234} AND ({2245} OR {2339})';
I need to get object like the following structure from above.
const output = {
and: [
2109,
{ or: [2370, 1071, 2702] },
1234,
{ or: [2245, 2339] },
];
Currently, I have tried to do like following
function parseFormat(strArg) {
var
category,
output = [], // Output
str = strArg.trim(); // Remove unwanted space before processing
str.split('AND').forEach(function(line) {
var removedString = line.replace(/[\])}[{(]/g, '');
var item = removedString.split('OR');
item = item.map(it => {
return Number(it.replace(/ /g, ''))
})
if(item.length > 0) {
output.push(item)
} else {
output.push(item[0])
}
});
return output;
}
And its output is like here.
[
[
1069
],
[
1070,
1071,
1072
],
[
1244
],
[
1245,
1339
]
]
I have one question first
How to add key AND and OR in the current result?
If you know a good solution on the performance side, please update me.
Thanks for taking the time.
const optionString = '{2109} AND ({2370} OR {1701} OR {2702}) AND {1234} AND ({2245} OR {2339})';
const parseExpr = s => {
let op, m, a = [];
while(s?.length) {
if(m = /^{(?<num>[0-9]+)}( (?<rest>.*))?/.exec(s)) {
a.push(+m.groups.num);
s = m.groups.rest;
}
else if(m = /^(?<op>[A-Z]+)( (?<rest>.*))?/.exec(s)) {
let t = m.groups.op.toLowerCase();
if(op && op!==t) throw new Error('Multiple operators cannot exist at same level in syntax tree')
else op = t;
s = m.groups.rest;
}
else if(s.startsWith('(')) {
for(let i=0, level=0; i<s.length; i++) {
if(s.charAt(i)==='(') level++;
if(s.charAt(i)===')') level--;
if(!level) {
a.push(parseExpr(s.substring(1, i)));
s = s.substring(i+2);
break;
}
if(i===s.length-1) throw new Error('Mismatched brackets')
}
}
else throw new Error(`Unparseable expression: ${s}`);
}
return { [op]: a };
}
const result = parseExpr(optionString)
console.log(result)

how to get the mentioned expected output from a object with nested objects

I have this data of objects ,
but unable to get expected output
we need to iterate on object children and print the name values in a particular order as given below
expected output :
kiran
vish
lav
mall
tried code :
let data = {
name: 'kiran',
children: [{
name: 'vish',
children: [{
name: 'lav',
children: []
},
{
name: 'mall',
children: []
}
]
}]
}
/* kiran
vish
lav
mall */
function indent(inputData) {
function indentHandler(inpData, level, output) {
if (!output) {
let output = '';
}
if (inpData.children.length) {
for (let i = 0; i < inpData.children.length; i++) {
level = level + 1;
console.log(addSpaces(level) + inpData.name + '\n');
indentHandler(inpData.children[i], level);
}
} else {
console.log(addSpaces(level) + inpData.name + '\n');
}
return output;
}
return indentHandler(inputData, 0, '');
}
function addSpaces(level) {
let outp = '';
for (let i = 0; i < level; i++) {
outp = outp + ' ';
}
return outp;
}
indent(data)
https://jsbin.com/yanogok/edit?js,console
please correct my program as I m unable to get correct output
Move your parent console.log out of loop
Do not change level in loop, just pass level + 1
let data = {
name: 'kiran',
children: [{
name: 'vish',
children: [{
name: 'lav',
children: []
},
{
name: 'mall',
children: []
}
]
}]
}
/* kiran
vish
lav
mall */
function indent(inputData) {
function indentHandler(inpData, level, output) {
if (!output) {
let output = '';
}
if (inpData.children.length) {
console.log(addSpaces(level) + inpData.name + '\n');
for (let i = 0; i < inpData.children.length; i++) {
indentHandler(inpData.children[i], level + 1);
}
} else {
console.log(addSpaces(level) + inpData.name + '\n');
}
return output;
}
return indentHandler(inputData, 0, '');
}
function addSpaces(level) {
let outp = '';
for (let i = 0; i < level; i++) {
outp = outp + ' ';
}
return outp;
}
indent(data)
function indent(data){
output = '';
return (function indentHandler(data, level){
output += addSpaces(level) + data['name'] + '\n';
if (data['children'].length === 0){
return output;
}
level += 1;
data['children'].forEach(function(child){
return indentHandler(child, level);
});
return output;
})(data, 0, '');
}
function addSpaces(level) {
let outp = '';
for (let i = 0; i < level; i++) {
outp = outp + ' ';
}
return outp;
}
indent(data)

Convert JSON to CSV and have the Headers be concatenations of the parents

I want to convert JSON responses to CSV format. Since the JSON response may differ, I can't manually create my headers.
I looked around and found a programmatic solution on stack overflow. But this solution uses the keys of the JSON as headers. My test data is sensitive so I'll post a similar JSON response that gives a better idea of what I'm trying to do.
{
"response":[{
"_id": "5cfe7d3c6deeeef08ce0444b",
"name": "Debra Milligain",
"phone": "+1 (906) 432-2182",
"address": "676 Merit Court, Steinhatchee, Oregon, 5491",
"tags": [
"consequat",
"reprehenderit",
"amet"
],
"Work": {
"skills": [{
"id": 0,
"name": "Programming"
},
{
"id": 1,
"name": "Business"
}
]
},
"friends": [{
"id": 0,
"name": "Stafford Hernandez"
},
{
"id": 1,
"name": "Colleen Christensen"
},
{
"id": 2,
"name": "Barker Keith"
}
],
"greeting": [],
"favoriteFruit": "banana"
}]}
Solution found from hereChristian Landgren 's Solution
function json2csv(json) {
const items = json.response;
const replacer = (key, value) => value === null ? '' : value // specify how you want to handle null values here
const header = Object.keys(items[0])
let csv = items.map(row => header.map(fieldName => JSON.stringify(row[fieldName], replacer)).join(','))
csv.unshift(header.join(','))
csv = csv.join('\r\n')
//console.log(csv)
}
This is the actual response:
_id,name,phone,address,tags,Work,friends,greeting,favoriteFruit
"5cfe7d3c6deeeef08ce0444b","Debra Milligain","+1 (906) 432-2182","676 Merit Court, Steinhatchee, Oregon, 5491",["consequat","reprehenderit","amet"],{"skills":[{"id":0,"name":"Programming"},{"id":1,"name":"Business"}]},[{"id":0,"name":"Stafford Hernandez"},{"id":1,"name":"Colleen Christensen"},{"id":2,"name":"Barker Keith"}],[],"banana"
The output as the headers but doesn't include the sub headers. The actual output should be this more or less.
"_id","name","phone","address","tags","Work__skills__id","Work__skills__name","friends__id","friends__name","favoriteFruit"
"5cfe7d3c6deeeef08ce0444b","Debra Milligain","+1 (906) 432-2182","676 Merit Court, Steinhatchee, Oregon, 5491","consequat","0","Programming","0","Stafford Hernandez","banana"
"","","","","reprehenderit","1","Business","1","Colleen Christensen",""
"","","","","amet","","","2","Barker Keith",""
What about more object oriented approach with recursion hidden in constructor ?
Made iterator - you can iterate 4 directions (next, prev, node, parent) and also 2 demo traverse of your sample data (log is too long for single output).
And in case you get private Current JNode out of iterator, you can list that container structure in any debugger where you can inspect variables (example VSC & node.js).
Separate IIFE code is in 3rd box.
DepthFirst demo:
'use strict';
function test(json) {
var it = new JIterator(json);
var i = 0;
var htmlTable = "<table border=1><tr><th>#</th><th>Level</th><th>Path</th><th>Key</th><th>Value or Type</th></tr>";
do {
htmlTable += "<tr><td>";
htmlTable += [i++, it.Level, it.Path().join('.'), it.KeyDots(), (it.Value() instanceof Object) ? (it.Value() instanceof Array ? "[]" : "{}") : it.Value()].join("</td><td>");
htmlTable += "</td></tr>";
} while (it.DepthFirst());
htmlTable += "</table>";
document.body.innerHTML = htmlTable;
}
var JNode = (function (jsNode) {
function JNode(_parent, _pred, _key, _value) {
this.parent = _parent;
this.pred = _pred;
this.node = null;
this.next = null;
this.key = _key;
this.value = _value;
}
return JNode;
})();
var JIterator = (function (json) {
var root, current, maxLevel = -1;
function JIterator(json, parent) {
if (parent === undefined) parent = null;
var pred = null, localCurrent;
for (var child in json) {
var obj = json[child] instanceof Object;
if(json instanceof Array) child = parseInt(child); // non-associative array
if (!root) root = localCurrent = new JNode(parent, null, child, json[child]);
else {
localCurrent = new JNode(parent, pred, child, obj ? ((json[child] instanceof Array) ? [] : {}) : json[child]);
}
if (pred) pred.next = localCurrent;
if (parent && parent.node == null) parent.node = localCurrent;
pred = localCurrent;
if (obj) {
var memPred = pred;
JIterator(json[child], pred);
pred = memPred;
}
}
if (this) {
current = root;
this.Level = 0;
}
}
JIterator.prototype.Current = function () { return current; }
JIterator.prototype.Parent = function () {
var retVal = current.parent;
if (retVal == null) return false;
this.Level--;
return current = retVal;
}
JIterator.prototype.Pred = function () {
var retVal = current.pred;
if (retVal == null) return false;
return current = retVal;
}
JIterator.prototype.Node = function () {
var retVal = current.node;
if (retVal == null) return false;
this.Level++;
return current = retVal;
}
JIterator.prototype.Next = function () {
var retVal = current.next;
if (retVal == null) return false;
return current = retVal;
}
JIterator.prototype.Key = function () { return current.key; }
JIterator.prototype.KeyDots = function () { return (typeof(current.key) == "number")?"":(current.key+':'); }
JIterator.prototype.Value = function () { return current.value; }
JIterator.prototype.Reset = function () {
current = root;
this.Level = 0;
}
JIterator.prototype.RawPath = function () {
var steps = [], level = current;
do {
if (level != null && level.value instanceof Object) {
steps.push(level.key + (level.value instanceof Array ? "[]" : "{}"));
} else {
if (level != null) steps.push(level.key);
else break;
}
level = level.parent;
} while (level != null);
var retVal = "";
retVal = steps.reverse();
return retVal;
}
JIterator.prototype.Path = function () {
var steps = [], level = current;
do {
if (level != null && level.value instanceof Object) {
var size = 0;
var items = level.node;
if(typeof(level.key) == "number") steps.push('[' + level.key + ']');
else {
while(items) {
size++;
items = items.next;
}
var type = (level.value instanceof Array ? "[]" : "{}");
var prev = steps[steps.length-1];
if(prev && prev[0] == '[') {
var last = prev.length-1;
if(prev[last] == ']') {
last--;
if(!isNaN(prev.substr(1, last))) {
steps.pop();
size += '.' + prev.substr(1, last);
}
}
}
steps.push(level.key + type[0] + size + type[1]);
}
} else {
if (level != null) {
if(typeof(level.key) == "number") steps.push('[' + level.key + ']');
else steps.push(level.key);
}
else break;
}
level = level.parent;
} while (level != null);
var retVal = "";
retVal = steps.reverse();
return retVal;
}
JIterator.prototype.DepthFirst = function () {
if (current == null) return 0; // exit sign
if (current.node != null) {
current = current.node;
this.Level++;
if (maxLevel < this.Level) maxLevel = this.Level;
return 1; // moved down
} else if (current.next != null) {
current = current.next;
return 2; // moved right
} else {
while (current != null) {
if (current.next != null) {
current = current.next;
return 3; // returned up & moved next
}
this.Level--;
current = current.parent;
}
}
return 0; // exit sign
}
JIterator.prototype.BreadthFirst = function () {
if (current == null) return 0; // exit sign
if (current.next) {
current = current.next;
return 1; // moved right
} else if (current.parent) {
var level = this.Level, point = current;
while (this.DepthFirst() && level != this.Level);
if (current) return 2; // returned up & moved next
do {
this.Reset();
level++;
while (this.DepthFirst() && level != this.Level);
if (current) return 3; // returned up & moved next
} while (maxLevel >= level);
return current != null ? 3 : 0;
} else if (current.node) {
current = current.node;
return 3;
} else if (current.pred) {
while (current.pred) current = current.pred;
while (current && !current.node) current = current.next;
if (!current) return null;
else return this.DepthFirst();
}
}
return JIterator;
})();
var json = {
"_id": "5cfe7d3c6deeeef08ce0444b",
"name": "Debra Milligain",
"phone": "+1 (906) 432-2182",
"address": "676 Merit Court, Steinhatchee, Oregon, 5491",
"tags": [
"consequat",
"reprehenderit",
"amet"
],
"Work": {
"skills": [
{
"id": 0,
"name": "Programming"
},
{
"id": 1,
"name": "Business"
}
]
},
"friends": [
{
"id": 0,
"name": "Stafford Hernandez"
},
{
"id": 1,
"name": "Colleen Christensen"
},
{
"id": 2,
"name": "Barker Keith"
}
],
"greeting": [],
"favoriteFruit": "banana"
}
test(json);
table {
border-spacing: 0px; /* small tricks 2 make rounded table simply or */
}
th {
text-align:left; /* centered looks ugly */
}
td.empty {
background-color:lightgray; /* mark null cells */
}
BreadthFirst demo:
'use strict';
function test(json) {
var it = new JIterator(json);
var i = 0;
var htmlTable = "<table border=1><tr><th>#</th><th>Level</th><th>Path</th><th>Key</th><th>Value or Type</th></tr>";
do {
htmlTable += "<tr><td>";
htmlTable += [i++, it.Level, it.Path().join('.'), it.KeyDots(), (it.Value() instanceof Object) ? (it.Value() instanceof Array ? "[]" : "{}") : it.Value()].join("</td><td>");
htmlTable += "</td></tr>";
} while (it.BreadthFirst())
htmlTable += "</table>";
document.body.innerHTML = htmlTable;
}
var JNode = (function (jsNode) {
function JNode(_parent, _pred, _key, _value) {
this.parent = _parent;
this.pred = _pred;
this.node = null;
this.next = null;
this.key = _key;
this.value = _value;
}
return JNode;
})();
var JIterator = (function (json) {
var root, current, maxLevel = -1;
function JIterator(json, parent) {
if (parent === undefined) parent = null;
var pred = null, localCurrent;
for (var child in json) {
var obj = json[child] instanceof Object;
if(json instanceof Array) child = parseInt(child); // non-associative array
if (!root) root = localCurrent = new JNode(parent, null, child, json[child]);
else {
localCurrent = new JNode(parent, pred, child, obj ? ((json[child] instanceof Array) ? [] : {}) : json[child]);
}
if (pred) pred.next = localCurrent;
if (parent && parent.node == null) parent.node = localCurrent;
pred = localCurrent;
if (obj) {
var memPred = pred;
JIterator(json[child], pred);
pred = memPred;
}
}
if (this) {
current = root;
this.Level = 0;
}
}
JIterator.prototype.Current = function () { return current; }
JIterator.prototype.Parent = function () {
var retVal = current.parent;
if (retVal == null) return false;
this.Level--;
return current = retVal;
}
JIterator.prototype.Pred = function () {
var retVal = current.pred;
if (retVal == null) return false;
return current = retVal;
}
JIterator.prototype.Node = function () {
var retVal = current.node;
if (retVal == null) return false;
this.Level++;
return current = retVal;
}
JIterator.prototype.Next = function () {
var retVal = current.next;
if (retVal == null) return false;
return current = retVal;
}
JIterator.prototype.Key = function () { return current.key; }
JIterator.prototype.KeyDots = function () { return (typeof(current.key) == "number")?"":(current.key+':'); }
JIterator.prototype.Value = function () { return current.value; }
JIterator.prototype.Reset = function () {
current = root;
this.Level = 0;
}
JIterator.prototype.RawPath = function () {
var steps = [], level = current;
do {
if (level != null && level.value instanceof Object) {
steps.push(level.key + (level.value instanceof Array ? "[]" : "{}"));
} else {
if (level != null) steps.push(level.key);
else break;
}
level = level.parent;
} while (level != null);
var retVal = "";
retVal = steps.reverse();
return retVal;
}
JIterator.prototype.Path = function () {
var steps = [], level = current;
do {
if (level != null && level.value instanceof Object) {
var size = 0;
var items = level.node;
if(typeof(level.key) == "number") steps.push('[' + level.key + ']');
else {
while(items) {
size++;
items = items.next;
}
var type = (level.value instanceof Array ? "[]" : "{}");
var prev = steps[steps.length-1];
if(prev && prev[0] == '[') {
var last = prev.length-1;
if(prev[last] == ']') {
last--;
if(!isNaN(prev.substr(1, last))) {
steps.pop();
size += '.' + prev.substr(1, last);
}
}
}
steps.push(level.key + type[0] + size + type[1]);
}
} else {
if (level != null) {
if(typeof(level.key) == "number") steps.push('[' + level.key + ']');
else steps.push(level.key);
}
else break;
}
level = level.parent;
} while (level != null);
var retVal = "";
retVal = steps.reverse();
return retVal;
}
JIterator.prototype.DepthFirst = function () {
if (current == null) return 0; // exit sign
if (current.node != null) {
current = current.node;
this.Level++;
if (maxLevel < this.Level) maxLevel = this.Level;
return 1; // moved down
} else if (current.next != null) {
current = current.next;
return 2; // moved right
} else {
while (current != null) {
if (current.next != null) {
current = current.next;
return 3; // returned up & moved next
}
this.Level--;
current = current.parent;
}
}
return 0; // exit sign
}
JIterator.prototype.BreadthFirst = function () {
if (current == null) return 0; // exit sign
if (current.next) {
current = current.next;
return 1; // moved right
} else if (current.parent) {
var level = this.Level, point = current;
while (this.DepthFirst() && level != this.Level);
if (current) return 2; // returned up & moved next
do {
this.Reset();
level++;
while (this.DepthFirst() && level != this.Level);
if (current) return 3; // returned up & moved next
} while (maxLevel >= level);
return current != null ? 3 : 0;
} else if (current.node) {
current = current.node;
return 3;
} else if (current.pred) {
while (current.pred) current = current.pred;
while (current && !current.node) current = current.next;
if (!current) return null;
else return this.DepthFirst();
}
}
return JIterator;
})();
var json = {
"_id": "5cfe7d3c6deeeef08ce0444b",
"name": "Debra Milligain",
"phone": "+1 (906) 432-2182",
"address": "676 Merit Court, Steinhatchee, Oregon, 5491",
"tags": [
"consequat",
"reprehenderit",
"amet"
],
"Work": {
"skills": [
{
"id": 0,
"name": "Programming"
},
{
"id": 1,
"name": "Business"
}
]
},
"friends": [
{
"id": 0,
"name": "Stafford Hernandez"
},
{
"id": 1,
"name": "Colleen Christensen"
},
{
"id": 2,
"name": "Barker Keith"
}
],
"greeting": [],
"favoriteFruit": "banana"
}
test(json);
table {
border-spacing: 0px; /* small tricks 2 make rounded table simply or */
}
th {
text-align:left; /* centered looks ugly */
}
td.empty {
background-color:lightgray; /* mark null cells */
}
My JScript iterators moved to GitHub
I ended up using my own solution and just recursively going down the JSON object. I made sure to keep track of key-value pairs that were at the root of the object vs those that weren't (since I would need to append their parent names to them). Furthermore, I used a hash table to make sure i don't have duplicate headers by making them keys and made their values just be actual values of that header append as a string separated by a ,
to later be parsed. Here's the code, I decided to leave the console logs just for others to debug and understand the process.
var arrayOfHeaders = {};
var headerDirectory = "";
var rootLevel = true;
var temp = ""
function traverseJSON(obj){
for (var o in obj) {
if (typeof obj[o] == "object") {
//console.log("Before traversal ", o)
//console.log("Traversing the object: ", obj[o])
if(!isNaN(o)){
//console.log("Current position is a number ", o)
}else{
//console.log("Adding to directory... " , o)
headerDirectory += (headerDirectory == "") ? o : "_" + o;
}
rootLevel = false;
traverseJSON(obj[o]);
rootLevel = true;
temp = headerDirectory;
headerDirectory = "";
} else {
if (rootLevel) {
headerDirectory = "";
//console.log("Has value and is root ", o)
arrayOfHeaders[headerDirectory];
}
else {
//console.log("Has value and is not root ", o)
//console.log("Current Header Directory " + headerDirectory)
//console.log("Saved temp : ", temp)
if(isNaN(o)){
if(headerDirectory == "") headerDirectory = temp;
//arrayOfHeaders.push(headerDirectory + "_" + o)
arrayOfHeaders[headerDirectory + "_" + o] += ",\"" + obj[o] + "\"";
}
}
}
}
// console.log("Array of Headers : ", arrayOfHeaders)
}
I used the same sample data provided in the question and the here's the contents of arrayOfHeaders after running the method.
Array of Headers : { 'Work_skills_id-skill': 'undefined,"0","Business"',
'Work_skills_name-skill': 'undefined,"Programming"',
'friends_id-friends': 'undefined,"0","1","2"',
'friends_name-friends':'undefined,"Stafford Hernandez","Colleen Christensen","Barker Keith"' }
Hopefully this helps others with a similar problem.

how to parse a .RC file using Javascript

I am trying to parse the data from a .RC (resource definition file) to JSON using js with simple fs.readFile function, however I am getting SyntaxError: Invalid or unexpected token. At the moment I've found no other solution to parse this type of file, pls provide me with inputs to do so. Below is .RC example.
#include "shapes.h"
ShapesCursor CURSOR SHAPES.CUR
ShapesIcon ICON SHAPES.ICO
ShapesMenu MENU
{
POPUP "&Shape"
{
MENUITEM "&Clear", ID_CLEAR
MENUITEM "&Rectangle", ID_RECT
}
}
I found a package in node called, 'Jison' which is an API for creating parsers in JavaScript similar to 'PegJS', however I couldn't figure out the grammer that needs to be written for my file type also if it would support the file type. The parsed structure could look similar to,
{
"directive": [
"include",
"shapes.h"
],
"data": [
{
"name": "ShapesCursor",
"values": [
"CURSOR",
"SHAPES.CUR"
],
"children": []
},
{
"name": "ShapesIcon",
"values": [
"CURSOR",
"SHAPES.ICO"
],
"children": []
},
{
"name": "POPUP",
"values": [
"&Shape"
],
"children": [
{
"name": "MENUITEM",
"values": [
"&Clear",
"ID_CLEAR"
],
"children": []
},
{
"name": "MENUITEM",
"values": [
"&Rectangle",
"ID_RECT"
],
"children": []
}
]
}
]
}
Below grammar can be used for parsing Resource Description files to a JSON.
{
var word_Obj = {};
var word_alnum_Obj = {};
var word_alnumsp_Obj = {};
var dir_Obj = {};
var valStateDec_Obj = {};
var stateName_Obj = {};
var valStateVal_Obj = {};
var word_Count = 0;
var word_alnum_Count = 0;
var word_alnumsp_Count = 0;
var dir_Count = -1;
var valStateDec_Count = 0;
var stateName_Count = -1;
var valStateVal_Count = -1;
var begin_Count = -1;
var end_Count = -1;
var child_Count = -1;
var children_Count = -1;
var flag = 0;
}
Expected = dir:directive * nl * states:state nl* Ending:EOL {if (begin_Count === end_Count) { return { Parsed_RC: { Directive_Obj: dir, States_Obj: states, ENDING: Ending } } } else { return "Incorrect .RC file" } }
directive = "#" d: word space* v:word_alnumsp nl+ { dir_Count++; dir_Obj = { ['Directive_' + dir_Count]: { "Dir": d, "_text": v } }; return dir_Obj;}
state = (valState looping)*
looping = (loopStart loopEnd*)*
loopStart = beg child: valState + { begin_Count++; children_Count++; child_Count++; return {['loopStart_' + begin_Count]: begin_Count, ['child_' + children_Count]: child } }
loopEnd = end {end_Count++; child_Count--; return { ['loopEnd_' + end_Count]: end_Count }; }
valState = stateName(valStateVal) * nl +
//valStateDec = space+ decState_val:word_alnumsp {valStateDec_Count++; valStateDec_Obj = {['ValStateDec_Obj'+valStateDec_Count]:decState_val}; return valStateDec_Obj;}
stateName = space * state_name:word_alnumsp {if (state_name === 'BEGIN') { begin_Count++; children_Count++; child_Count++; return { ['loopStart_' + begin_Count]: begin_Count } } if (state_name === 'END') { end_Count++; child_Count--; return { ['loopEnd_' + end_Count]: end_Count }; } if (child_Count < 0) { flag = 1; } stateName_Count++; stateName_Obj = { ['StateName_Obj' + stateName_Count]: state_name }; return stateName_Obj; }
valStateVal = space + valState_val:(word_alnumsp comma?)* { valStateVal_Count++; valStateVal_Obj = { ['_attributes_Obj' + valStateVal_Count]: valState_val }; return valStateVal_Obj}
word = wo:letter + { return wo.join("") }
word_alnum = al:alnum + { return al.join("") }
word_alnumsp = alsp:alnumsp + { return alsp.join("") }
beg = space * ([{]) space* nl +
end = space * ([}]) space* nl +
comma = space * [,] space* { return ","}
letter = [a - zA - Z]
alnum = [a - zA - Z0 - 9]
alnumsp = [a - zA - Z0 - 9"'&._()\\|+:]
space = " "
nl = '\n' {valStateVal_Count = -1; return "NL"}
EOL = !. {return "EOF"}

Group or rearrange array elements based on a condition - javascript

I have an array called 'country' which looks like:
country=[
{
"name": "china",
"id": "country:china"
}, {
"name": "city1",
"id": "country:country1>city1"
}, {
"name": "city2",
"id": "country:country1>city2"
}, {
"name": "city3",
"id": "country:country1>city3"
}, {
"name": "korea",
"id": "country:korea"
}, {
"name": "australia",
"id": "country:australia"
}
]
I am looking at rearranging/grouping the above array as:
countryResult = [ china, country1(city1, city2, city3), korea, australia]
I have written the following code but this does not give me the desired result:
$scope.countryInfo = function(itemData){
var countryResult = [];
for(var i=0; i<itemData.length; i++){
var countryItem = itemData[i];
if(countryItem.id.indexOf('>') > -1){ //Found city
var itemId = countryItem.id.substr(0, countryItem.id.indexOf('>'));
for(var j=0; j<$scope.countryData.length; j++){
if($scope.countryData[j].id == itemId){
var _parentChild = $scope.countryData[j].name + "( " + countryItem.name + " ) ";
countryResult.push(_parentChild);
}
}
}
else{
countryResult.push(countryItem.name);
}
}
return countryResult;
}
The result is coming up like this - [ china, country1(city1), country1(city2), country1(city3)), korea, australia]
Please let me know how to achieve the expected array result.
EDIT: I am just looking at simplifying the array [ china, country1(city1), country1(city2), country1(city3)), korea, australia] to [ china, country1(city1, city2, city3), korea, australia]
I've used reduce with an initial object with a keys property to capture the positions of the elements:
function sorter(countty) {
var obj = country.reduce(function (p, c, i) {
var key, id = c.id.split(/[:>]/);
if (id.length === 3) {
key = id[1];
if (!p[key]) {
p[key] = [];
p.keys.push(key);
}
p[key].push(id[2]);
} else {
p.keys.push(c.name);
}
return p;
}, { keys: [] });
return obj.keys.map(function (el) {
return obj[el] ? el + '(' + obj[el].join(', ') + ')' : el;
});
}
sorter(country);
DEMO
You can use a temporary object and then map the object's properties to the wanted array.
var country = [{ "name": "china", "id": "country:china" }, { "name": "city1", "id": "country:country1>city1" }, { "name": "city2", "id": "country:country1>city2" }, { "name": "city3", "id": "country:country1>city3" }, { "name": "korea", "id": "country:korea" }, { "name": "australia", "id": "country:australia" }],
temp = {},
result;
country.forEach(function (a) {
var b = a.id.split(/\:|\>/g);
temp[b[1]] = temp[b[1]] || [];
if (b[2]) {
temp[b[1]].push(b[2]);
}
});
result = Object.keys(temp).map(function (k) {
if (temp[k].length) {
return k + '(' + temp[k].join(', ') + ')';
}
return k;
});
document.write('<pre>' + JSON.stringify(result, 0, 4) + '</pre>');
I wrote this bit of code to change your first array (in your "EDIT") into your second array, I'm not saying it's clean, but it works:
sorts the array, then tries to figure out if the countries match, and if they have cities that need to be merged...
//an array of countries, some of which include comma delimited cities wrappedin parentheses
var arrayPlaces = ["china", "country1(city1)", "korea", "country1", "country1(city2)", "country1(city3)", "australia", "korea", "home(delicious)", "home(nacho)", "home(plate)"];
//creates an alphabatized version of the array, to simplify finding matching countries
var arrayPlacesSorted = arrayPlaces.sort();
//defines a regular expression (to search for matches countries)
var hasCity = function (sTemp) {
var re = /\(/;
if (re.test(sTemp)) {
return true;
} else {
return false;
}
};
var countryRe = /(.*?)\(.*?\)/;
var cityRe = /.*?\((.*?)\)/;
//function that loops through array, checks for matching countries, combines/adds cities
var groupCities = function (aTemp) {
var currentCountry,
currentCity,
nextCountry,
nextCity;
for (var i = 0; i < (aTemp.length); i++) {
if (hasCity(aTemp[i])) {
currentCountry = countryRe.exec(aTemp[i])[1];
currentCity = cityRe.exec(aTemp[i])[1];
} else {
currentCountry = aTemp[i];
currentCity = false;
}
if (hasCity(aTemp[i + 1])) {
nextCountry = countryRe.exec(aTemp[i + 1])[1];
nextCity = cityRe.exec(aTemp[i + 1])[1];
} else {
nextCountry = aTemp[i + 1];
nextCity = false;
}
if (currentCountry === nextCountry && nextCity && currentCity) {
aTemp[i] = currentCountry + "(" + currentCity + "," + nextCity + ")";
aTemp.splice(i + 1, 1);
i = 0;
} else if (currentCountry === nextCountry && nextCity) {
aTemp[i] = currentCountry + "(" + nextCity + ")";
aTemp.splice(i + 1, 1);
i = 0;
} else if (currentCountry === nextCountry && currentCity) {
aTemp[i] = currentCountry + "(" + currentCity + ")";
aTemp.splice(i + 1, 1);
i = 0;
} else if (currentCountry === nextCountry) {
aTemp[i] = currentCountry;
aTemp.splice(i + 1, 1);
i = 0;
}
}
return aTemp;
};
var result = groupCities(arrayPlacesSorted);
console.log(result);

Categories