How to convert an array of paths into JSON structure? - javascript

I found the question How to convert a file path into treeview?, but I'm not sure how to get the desired result in JavaScript:
I'm trying to turn an array of paths into a JSON tree:
https://jsfiddle.net/tfkdagzv/16/
But my path is being overwritten.
I'm trying to take something like this:
[
'/org/openbmc/path1',
'/org/openbmc/path2',
...
]
... and turn it into...
output = {
org: {
openbmc: {
path1: {},
path2: {}
}
}
}
I'm sure this is pretty easy, but I'm missing something.

const data = [
"/org/openbmc/examples/path0/PythonObj",
"/org/openbmc/UserManager/Group",
"/org/openbmc/HostIpmi/1",
"/org/openbmc/HostServices",
"/org/openbmc/UserManager/Users",
"/org/openbmc/records/events",
"/org/openbmc/examples/path1/SDBusObj",
"/org/openbmc/UserManager/User",
"/org/openbmc/examples/path0/SDBusObj",
"/org/openbmc/examples/path1/PythonObj",
"/org/openbmc/UserManager/Groups",
"/org/openbmc/NetworkManager/Interface"
];
const output = {};
let current;
for (const path of data) {
current = output;
for (const segment of path.split('/')) {
if (segment !== '') {
if (!(segment in current)) {
current[segment] = {};
}
current = current[segment];
}
}
}
console.log(output);
Your solution was close, you just didn't reset the current variable properly. Use this:
current = output;
instead of this:
current = output[path[0]];

This function should do :
var parsePathArray = function() {
var parsed = {};
for(var i = 0; i < paths.length; i++) {
var position = parsed;
var split = paths[i].split('/');
for(var j = 0; j < split.length; j++) {
if(split[j] !== "") {
if(typeof position[split[j]] === 'undefined')
position[split[j]] = {};
position = position[split[j]];
}
}
}
return parsed;
}
Demo
var paths = [
"/org/openbmc/UserManager/Group",
"/org/stackExchange/StackOverflow",
"/org/stackExchange/StackOverflow/Meta",
"/org/stackExchange/Programmers",
"/org/stackExchange/Philosophy",
"/org/stackExchange/Religion/Christianity",
"/org/openbmc/records/events",
"/org/stackExchange/Religion/Hinduism",
"/org/openbmc/HostServices",
"/org/openbmc/UserManager/Users",
"/org/openbmc/records/transactions",
"/org/stackExchange/Religion/Islam",
"/org/openbmc/UserManager/Groups",
"/org/openbmc/NetworkManager/Interface"
];
var parsePathArray = function() {
var parsed = {};
for(var i = 0; i < paths.length; i++) {
var position = parsed;
var split = paths[i].split('/');
for(var j = 0; j < split.length; j++) {
if(split[j] !== "") {
if(typeof position[split[j]] === 'undefined')
position[split[j]] = {};
position = position[split[j]];
}
}
}
return parsed;
}
document.body.innerHTML = '<pre>' +
JSON.stringify(parsePathArray(), null, '\t')
'</pre>';
(see also this Fiddle)

NB: The resulting arrays need to be merged
This method works for both files & directories, and by using only arrays as the data format.
The structure is based upon arrays being folders, the first element being the folder name and the second - the contents array.
Files are just regular strings inside the array (but could easily be objects containing properties)
Converts =>
[
'/home/',
'/home/user/.bashrc',
'/var/',
'/var/test.conf',
'/var/www/',
'/var/www/index.html',
'/var/www/index2.html'
]
To =>
[
['home', [
['user', [
'.bashrc'
]]
]],
['var', [
'test.conf',
['www', [
'index.html',
'index2.html'
]]
]]
]
Script:
var paths = [
'/var/',
'/var/test.conf',
'/var/www/',
'/var/www/index.html',
'/var/www/index2.html'
]
var parsed = []
for (let path of paths) {
let tree = path.split('/')
let previous = parsed
console.groupCollapsed(path)
for (let item in tree) {
const name = tree[item]
const last = item == tree.length - 1
if (name) {
if (last) {
console.log('File:', name)
previous.push(name) - 1
} else {
console.log('Folder:', name)
let i = previous.push([name, []]) - 1
previous = previous[i][1]
}
}
}
console.groupEnd(path)
}
console.warn(JSON.stringify(parsed))

Related

Javascript Parsing Key Value String to JSON

I'm currently working on trying to create a UDF to split a key value pair string based on web traffic into JSON.
I've managed to get as far as outputting a JSON object but I'd like to be able to dynamically add nested items based on the number of products purchased or viewed based on the index number of the key.
When a product is only viewed, there is always only one product in the string. Only when its a transaction is it more than one but I think it would be good to conform the structure of the json and then identify a purchase or view based on the presence of a transactionid. For example:
Item Purchased:
sessionid=12345&transactionid=555555&product1=apples&productprice1=12&product1qty=1&product2=pears&productprice2=23&product2qty=3&transactionamount=58
The output should look something like this:
[
{
"sessionid":12345,
"transactionid":555555,
"transactionamount":58
},
[
{
"productline":1,
"product":"apples",
"productprice":12,
"productqty":1
},
{
"productline":2,
"product":"pears",
"productprice":23,
"productqty":2
}
]
]
Item Viewed:
sessionid=12345&product1=apples&productprice1=12&product1qty=1&product2=pears&productprice2=23&product2qty=3
[
{
"sessionid":12345,
"transactionid":0,
"transactionamount":0
},
[
{
"productline":1,
"product":"apples",
"productprice":12,
"productqty":1
}
]
]
The result I'll be able to parse from JSON into a conformed table in a SQL table.
What I've tried so far is only parsing the string, but its not ideal to create a table in SQL because the number of purchases can vary:
var string = "sessionid=12345&transactionid=555555&product1=apples&productprice1=12&product1qty=1&product2=pears&productprice2=23&product2qty=3&transactionamount=58";
function splitstring(queryString) {
var dictionary = {};
if (queryString.indexOf('?') === 0) {
queryString = queryString.substr(1);
}
var parts = queryString.split('&');
for (var i = 0; i < parts.length; i++) {
var p = parts[i];
// Step 2: Split Key/Value pair
var keyValuePair = p.split('=');
var key = keyValuePair[0];
var value = keyValuePair[1];
dec_val = decodeURIComponent(value);
final_value = dec_val.replace(/\+/g, ' ');
dictionary[key] = final_value;
}
return (dictionary);
}
console.log(splitstring(string));
Thanks in advance!!!
Feel like this would be less clunky with better param naming conventions, but here's my take...
function parseString(string) {
var string = string || '',
params, param, output, i, l, n, v, k, pk;
params = string.split('&');
output = [{},
[]
];
for (i = 0, l = params.length; i < l; i++) {
param = params[i].split('=');
n = param[0].match(/^product.*?([0-9]+).*/);
v = decodeURIComponent(param[1] || '');
if (n && n[1]) {
k = n[1];
output[1][k] = output[1][k] || {};
output[1][k]['productline'] = k;
pk = n[0].replace(/[0-9]+/, '');
output[1][k][pk] = v;
} else {
output[0][param[0]] = v;
}
}
output[1] = output[1].filter(Boolean);
return output;
}
var string = "sessionid=12345&transactionid=555555&product1=apples&productprice1=12&product1qty=1&product2=pears&productprice2=23&product2qty=3&transactionamount=58";
console.log(parseString(string));
output:
[
{
"sessionid": "12345",
"transactionid": "555555",
"transactionamount": "58"
},
[{
"productline": "1",
"product": "1",
"productprice": "12"
}, {
"productline": "2",
"product": "3",
"productprice": "23"
}]
]
There's probably a far nicer way to do this, but I just wrote code as I thought about it
var string = "sessionid=12345&transactionid=555555&product1=apples&productprice1=12&product1qty=1&product2=pears&productprice2=23&product2qty=3&transactionamount=58";
function splitstring(queryString) {
var dictionary = {};
if (queryString.indexOf('?') === 0) {
queryString = queryString.substr(1);
}
var parts = queryString.split('&');
for (var i = 0; i < parts.length; i++) {
var p = parts[i];
// Step 2: Split Key/Value pair
var keyValuePair = p.split('=');
var key = keyValuePair[0];
var value = keyValuePair[1];
dec_val = decodeURIComponent(value);
final_value = dec_val.replace(/\+/g, ' ');
dictionary[key] = final_value;
}
return (dictionary);
}
function process(obj) {
let i = 1;
const products = [];
while(obj.hasOwnProperty(`product${i}`)) {
products.push({
[`product`]: obj[`product${i}`],
[`productprice`]: obj[`productprice${i}`],
[`productqty`]: obj[`product${i}qty`]
});
delete obj[`product${i}`];
delete obj[`productprice${i}`];
delete obj[`product${i}qty`];
++i;
}
return [obj, products];
}
console.log(process(splitstring(string)));
By the way, if this is in the browser, then splitstring can be "replaced" by
const splitstring = string => Object.fromEntries(new URLSearchParams(string).entries());
var string = "sessionid=12345&transactionid=555555&product1=apples&productprice1=12&product1qty=1&product2=pears&productprice2=23&product2qty=3&transactionamount=58";
function process(string) {
const splitstring = queryString => {
var dictionary = {};
if (queryString.indexOf('?') === 0) {
queryString = queryString.substr(1);
}
var parts = queryString.split('&');
for (var i = 0; i < parts.length; i++) {
var p = parts[i];
// Step 2: Split Key/Value pair
var keyValuePair = p.split('=');
var key = keyValuePair[0];
var value = keyValuePair[1];
dec_val = decodeURIComponent(value);
final_value = dec_val.replace(/\+/g, ' ');
dictionary[key] = final_value;
}
return (dictionary);
};
let i = 1;
const obj = splitstring(string);
const products = [];
while (obj.hasOwnProperty(`product${i}`)) {
products.push({
[`product`]: obj[`product${i}`],
[`productprice`]: obj[`productprice${i}`],
[`productqty`]: obj[`product${i}qty`]
});
delete obj[`product${i}`];
delete obj[`productprice${i}`];
delete obj[`product${i}qty`];
++i;
}
return [obj, products];
}
console.log(process(string));

How to convert an array into a hierarchical array

I have some data which is
var currentData = [
{'ticket':'CAP', 'child':'CT-1'},
{'ticket':'CAP', 'child':'CT-2'},
{'ticket':'CT-1', 'child':'CT-1-A'},
{'ticket':'CT-1', 'child':'CT-1-B'}
];
The data is flat and I need to convert it into something like:
{
'ticket': 'CAP',
children : [{
'ticket' : 'CT-1',
'children' : [{
'ticket' : 'CT-1-A',
'children' : []
}, {
'ticket' : 'CT-1-B',
'children' : []
}],
[{
'ticket' : 'CT-2',
'children' : []
}]
}]
}
(I think the above is valid)?
I'm very lost as to how. I am going to show my effort but, I'm not sure if my approach is correct or not.
var currentData = [{'ticket':'cap', 'child':'CT-1'},{'ticket':'cap', 'child':'CT-2'}, {'ticket':'CT-1', 'child':'CT-1-A'},{'ticket':'CT-1', 'child':'CT-1-B'}];
var newList = [];
function convert(list){
if (newList.length <= 0){
var child = [];
var emptyChild = [];
child.push({'ticket': list[0].child, 'child': emptyChild });
newList.push({'ticket': list[0].ticket, 'children' : child});
list.splice(0,1);
} // the if statement above works fine
for(var i = 0; i < list.length; i++) {
var ticket = list[i].ticket;
for(var j = 0; j < newList.length; j++) {
if (newList[j].ticket == ticket){
var child;
var emptyChild = [];
child = {'ticket': list[i].child, 'child': emptyChild };
newList[j].children.push(child);
list.splice(i,1);
break;
} // the if above works
else{
var child2 = getFromChildren(ticket, newList, list[i]); // child2 is Always null, even if getFromChildren returns an object
newList[j].children.push(child2);
list.splice(i,1);
break;
}
}
}
if (list.length > 0){
convert(list);
}
}
function getFromChildren(ticket, list, itemToAdd){
if (list == null || list[0].children == null)
return;
for(var i = 0; i < list.length; i++) {
if (list[i] == null)
return;
if (list[i].ticket == ticket){
list[i].child.push(itemToAdd.child); // ** can't do this, javascript passes by value, not by reference :(
} else{
getFromChildren(ticket, list[i].children, itemToAdd);
}
}
}
convert(currentData);
I think I've made a mess of it. In the comments I've put a ** explaining that it isn't working due to JavaScript not passing by reference, however upon further reading I don't think that is correct as I'm passing the object which is by reference?
Edit
The data, shown with currentData will not always start at the root sadly either
function convert(arr) {
var children = {}; // this object will hold a reference to all children arrays
var res = arr.reduce(function(res, o) { // for each object o in the array arr
if(!res[o.ticket]) { // if there is no object for the element o.ticket
res[o.ticket] = {ticket: o.ticket, children: []}; // then creates an object for it
children[o.ticket] = res[o.ticket].children; // and store a reference to its children array
}
if(!res[o.child]) { // if there is no object for the element o.child
res[o.child] = {ticket: o.child, children: []}; // then creates an object for it
children[o.child] = res[o.child].children; // and store a reference to its children array
}
return res;
}, {});
arr.forEach(function(o) { // now for each object o in the array arr
children[o.ticket].push(res[o.child]); // add the object of o.child (from res) to its children array
delete res[o.child]; // and remove the child object from the object res
});
return res;
}
var currentData = [
{'ticket':'CAP', 'child':'CT-1'},
{'ticket':'CAP', 'child':'CT-2'},
{'ticket':'CT-1', 'child':'CT-1-A'},
{'ticket':'CT-1', 'child':'CT-1-B'}
];
console.log(convert(currentData));
Explanation:
The reduce part creates an object of the form: { ticket: "...", children: [] } for each element (child or not). So right after reduce, the object res will be:
res = {
'CAP': { ticket: 'CAP', children: [] },
'CT-1': { ticket: 'CT-1', children: [] },
'CT-2': { ticket: 'CT-2', children: [] },
'CT-1-A': { ticket: 'CT-1-A', children: [] },
'CT-1-B': { ticket: 'CT-1-B', children: [] },
}
Now comes the forEach bit which loops over the array once more, and now for each object it fetches the object of .child from res above, push it into .ticket object's children (which a reference to it is stored in children object), then remove the .child object from the object res.
Below uses reduce to get the data grouped to a Map, then I convert the data to an object like you've shown above. You'll need a modern browser to run below snippet, or use a transpiler like babeljs to convert it to es5 syntax.
let currentData = [
{'ticket':'CAP', 'child':'CT-1'},
{'ticket':'CAP', 'child':'CT-2'},
{'ticket':'CT-1', 'child':'CT-1-A'},
{'ticket':'CT-1', 'child':'CT-1-B'}
];
let children = currentData.map(e => e.child);
currentData.sort((a,b) => children.indexOf(a.ticket));
let res = currentData.reduce((a,b) => {
if (! children.includes(b.ticket)) {
return a.set(b.ticket, (a.get(b.ticket) || [])
.concat({ticket: b.child,
children: currentData
.filter(el => el.ticket === b.child)
.map(el => ({ticket: el.child, children: []}))}))
}
return a;
}, new Map);
let r = {};
for (let [key,value] of res.entries()) {
r.ticket = key;
r.children = value;
}
console.log(r);
Solution using recursion, starting node can be changed.
var currentData = [{'ticket': 'cap','child': 'CT-1'}, {'ticket': 'cap','child': 'CT-2'}, {'ticket': 'CT-1','child': 'CT-1-A'}, {'ticket': 'CT-1','child': 'CT-1-B'}];
function convert(data, start){
return {
ticket: start,
childs: data.filter(d => d.ticket == start)
.reduce((curr, next) => curr.concat([next.child]), [])
.map(c => convert(data, c))
}
}
let result = convert(currentData, 'cap');
console.log(result);
.as-console-wrapper{top: 0; max-height: none!important;}
I would go with a simple for approach, like this:
var currentData = [
{'ticket':'CAP', 'child':'CT-1'},
{'ticket':'CAP', 'child':'CT-2'},
{'ticket':'CT-1', 'child':'CT-1-A'},
{'ticket':'CT-1', 'child':'CT-1-B'}
];
var leafs = {};
var roots = {};
var tickets = {};
for(var i=0; i<currentData.length; i++){
var ticket = currentData[i].ticket;
var child = currentData[i].child;
if(!tickets[ticket]){
tickets[ticket] = {ticket:ticket,children:[]};
if(!leafs[ticket]){
roots[ticket] = true;
}
}
if(!tickets[child]){
tickets[child] = {ticket:child,children:[]};
}
delete roots[child];
leafs[child] = true;
tickets[ticket].children.push(tickets[child]);
}
for(var ticket in roots){
console.log(tickets[ticket]);
}
Well, if you are not familiar with reduce, map , forEach with callbacks to iterate, then here is a approach I came with, where the code is flat, storing object references in another map object and iterating exactly once the source array.
The code is much cleaner, if something is understandable add comments I will explain;
var currentData = [
{'ticket':'CT-1', 'child':'CT-1-A'},
{'ticket':'CT-1', 'child':'CT-1-B'},
{'ticket':'CAP', 'child':'CT-1'},
{'ticket':'CAP', 'child':'CT-2'}
];
function buildHierarchy(flatArr) {
let root = {},
nonRoot = {},
tempMap = {};
Object.setPrototypeOf(root, nonRoot);
for (let idx = 0; idx < flatArr.length; idx++) {
let currTicket = flatArr[idx];
let tempTicket = tempMap[currTicket.ticket] || {ticket: currTicket.ticket, children: []};
tempMap[currTicket.ticket] = tempTicket;
if (currTicket.child) {
let tempChild = tempMap[currTicket.child] || {ticket: currTicket.child, children: []};
tempTicket.children.push(tempChild);
tempMap[currTicket.child] = tempChild;
delete root[tempChild.ticket];
nonRoot[tempChild.ticket] = true;
}
root[tempTicket.ticket] = true;
}
return tempMap[Object.keys(root)[0]];
}
console.log(buildHierarchy(currentData));
I have changed the sequence of your source array in order to put the root object anywhere, and the code should work on that.

Push different object in an array with a for loop

I have an element structured like this:
Element ->
[{values: arrayOfObject, key:'name1'}, ... ,{values: arrayOfObjectN, key:'nameN'}]
arrayDiObject -> [Object1, Object2, ... , ObjectN] //N = number of lines in my CSV
Object1 -> {x,y}
I have to take data from a big string:
cityX#substanceX#cityY#substanceY#
I thought to make it this way, but it seems like it pushes always in the same array of objects. If I put oggetto = {values: arrayDateValue, key: key}; inside the d3.csv function, instead if I put outside the function it add me only empty objects.
Here is my code:
var final = new Array();
var oggetto;
var key;
function creaDati() {
var newdate;
var arrayDateValue = new Array();
var selString = aggiungiElemento().split("#");
//selString is an array with selString[0]: city, selString[1]: substance and so on..
var citySelected = "";
var substanceSelected = "";
for (var i = 0; i < selString.length - 1; i++) {
if (i % 2 === 0) {
citySelected = selString[i];
} else if (i % 2 !== 0) {
substanceSelected = selString[i];
key = citySelected + "#" + substanceSelected;
d3.csv("/CSV/" + citySelected + ".csv", function(error, dataset) {
dataset.forEach(function(d) {
arrayDateValue.push({
x: d.newdate,
y: d[substanceSelected]
});
});
});
oggetto = {
values: arrayDateValue,
key: key
};
arrayDateValue = [];
final.push(oggetto);
}
}
}
Any idea ?
First you should make the if statement for the city and then for the key, which you seem to be doing wrong since you want the pair indexes to be the keys and the not pair to be the city, and you are doing the opposite. And then you need to have the d3.csv and push the objects outside of the if statement, otherwise in your case you are just adding elements with citySelected="".
Try something like :
for(var i = 0; i < selString.length -1; i+=2){
cittySelected = selString[i];
substanceSelected = selString[i+1];
key = citySelected + "#" + substanceSelected;
d3.csv("/CSV/"+citySelected+".csv", function(error, dataset){
dataset.forEach(function(d){
arrayDateValue.push({x: d.newdate, y: d[substanceSelected]});
});
});
oggetto = {values: arrayDateValue, key: key};
arrayDateValue = [];
final.push(oggetto);
}
It's is not the best way to do it, but it is clearer that what you are following, i think.
In the if(i % 2 == 0) { citySelected = ... } and else if(i % 2 !== 0) { substanceSelected = ... } citySelected and substanceSelected will never come together.
The values should be in one statement:
if(...) { citySelected = ...; substanceSelected = ...; }
The string can be splitted into pairs
city1#substance1, city2#substance2, ...
with a regex (\w{1,}#\w{1,}#).
Empty the arrayDateValue after the if-statement.
Hint:
var str = "cityX#substanceX#cityY#substanceY#";
function createArr(str) {
var obj = {};
var result = [];
var key = "";
// '', cityX#substanceX, '', cityYsubstanceY
var pairs = str.split(/(\w{1,}#\w{1,}#)/g);
for (var i = 0; i < pairs.length; i++) {
if(i % 2 !== 0) {
key = pairs[i];
// d3 stuff to create values
obj = {
// Values created with d3 placeholder
values: [{x: "x", y: "y"}],
// Pair
key: key
};
result.push(obj);
}
// Here should be values = [];
}
return result;
}
var r = createArr(str);
console.log(r);
May be you can do like this;
var str = "cityX#substanceX#cityY#substanceY",
arr = str.split("#").reduce((p,c,i,a) => i%2 === 0 ? p.concat({city:c, key:a[i+1]}) : p,[]);
console.log(JSON.stringify(arr));
RESOLVED-
The problem is about d3.csv which is a asynchronous function, it add in the array when it finish to run all the other code.
I make an XMLHttpRequest for each csv file and it works.
Hope it helps.

Add or remove element(s) to array

I have an existing array of objects :
existingArray = [
{object1: 'object1'},
{object2: 'object2'}
{object3: 'object3'},
]
I receive a new one :
newArray = [
{object2: 'object2'},
{object3: 'object3'},
{object4: 'object4'}
]
I want only to modify the existing one to get the new one as the result (push+splice)
Here is what I have for now (is there a better way ?)
for (var i = 0; i < newArray.length; i++) {
// loop first to push new elements
var responseToTxt = JSON.stringify(newArray[i]);
var newStatement = false;
for(var j = 0; j < existingArray.length; j++){
var statementToTxt = JSON.stringify(existingArray[j]);
if(statementToTxt === responseToTxt && !newStatement){
newStatement = true;
}
}
if(!newStatement){
statements.push(response[i]);
}
}
var statementsToSplice = [];
for (var i = 0; i < existingArray.length; i++) {
// then loop a second time to split elements not anymore on the new array
var statementToTxt = JSON.stringify(existingArray[i]);
var elementPresent = false;
var element = false;
for(var j = 0; j < newArray.length; j++){
var responseToTxt = JSON.stringify(newArray[j]);
if(responseToTxt === statementToTxt && !elementPresent){
elementPresent = true;
} else {
element = i;
}
}
if(!elementPresent){
statementsToSplice.push(element);
}
}
Then I needed to split multiple times in the array :
existingArray = statementsToSplice.reduceRight(function (arr, it) {
arr.splice(it, 1);
return arr;
}, existingArray.sort(function (a, b) { return b - a }));
Here is the example :
https://jsfiddle.net/docmz22b/
So the final output should always be the new array, but only by push or splice the old one.
In this case, the final outpout will be
existingArray = [
{object2: 'object2'},
{object3: 'object3'}
{object4: 'object4'},
]
The new array could contains multiple new elements and/or deleted elements that is currently in the existingArray
Use shift() and push()
existingArray.shift(); //Removes the first element of the array
existingArray.push({'object4' : 'object4'});
Fiddle
I'm almost 100% sure that there is a better way to do it, but at least this works, feel free to comment any suggestions / optimizations.
existingArray = [
{object1: 'object1'},
{object2: 'object2'},
{object3: 'object3'}
];
newArray = [
{object2: 'object2'},
{object3: 'object3'},
{object4: 'object4'}
];
// Loop all the old values, if is not in the new array, remove it
existingArray.forEach(function(item) {
if(!inArray(item, newArray)) {
var idx = indexOfObjectInArray(item, existingArray);
existingArray.splice(idx, 1);
}
});
// Loop all the new values, if is not in the new array, push it
newArray.forEach(function(item) {
if (!inArray(item, existingArray)) {
existingArray.push(item);
}
});
// Auxiliar functions
function inArray(initialValue, array) {
testValue = JSON.stringify(initialValue);
return array.some(function(item) {
return testValue == JSON.stringify(item);
});
}
function indexOfObjectInArray(initialValue, array) {
var result = -1;
testValue = JSON.stringify(initialValue);
array.forEach(function(item, idx) {
if (testValue == JSON.stringify(item)) {
result = idx;
};
});
return result;
}
Maybe this helps. It features Array.prototype.forEach and Array.prototype.some.
Splice unwanted items
Look if object with same property exist
If yes, then assign new object
Else push the object
var existingArray = [
{ object1: 'object1' },
{ object2: 'object2' },
{ object3: 'object3' },
],
newArray = [
{ object2: 'object22' },
{ object3: 'object33' },
{ object4: 'object44' }
];
function update(base, change) {
var changeKeys = change.map(function (a) { return Object.keys(a)[0]; }),
i = 0;
while (i < base.length) {
if (!~changeKeys.indexOf(Object.keys(base[i])[0])) {
base.splice(i, 1);
continue;
}
i++;
}
change.forEach(function (a) {
var aKey = Object.keys(a)[0];
!base.some(function (b, i, bb) {
if (aKey === Object.keys(b)[0]) {
bb[i] = a; // if that does not work, use bb.splice(i, 1, a);
return true;
}
}) && base.push(a);
});
}
update(existingArray, newArray);
document.write('<pre>' + JSON.stringify(existingArray, 0, 4) + '</pre>');

Javascript Recursion for creating a JSON object

needing some advice on how to do this properly recursively.
Basically what I'm doing, is entering in a bunch of text and it returns it as JSON.
For example:
The text:
q
b
name:rawr
Returns:
[
"q",
"b",
{
"name": "rawr"
}
]
And the following input:
q
b
name:rawr:awesome
Would return (output format is not important):
[
"q",
"b",
{
"name": {
"rawr": "awesome"
}
}
]
How can I modify the following code to allow a recursive way to have objects in objects.
var jsonify = function(input){
var listItems = input, myArray = [], end = [], i, item;
var items = listItems.split('\r\n');
// Loop through all the items
for(i = 0; i < items.length; i++){
item = items[i].split(':');
// If there is a value, then split it to create an object
if(item[1] !== undefined){
var obj = {};
obj[item[0]] = item[1];
end.push(obj);
}
else{
end.push(item[0]);
}
}
// return the results
return end;
};
I don't think recursion is the right approach here, a loop could do that as well:
var itemparts = items[i].split(':');
var value = itemparts.pop();
while (itemparts.length) {
var obj = {};
obj[itemparts.pop()] = value;
value = obj;
}
end.push(value);
Of course, as recursion and loops have equivalent might, you can do the same with a recursive function:
function recurse(parts) {
if (parts.length == 1)
return parts[0];
// else
var obj = {};
obj[parts.shift()] = recurse(parts);
return obj;
}
end.push(recurse(items[i].split(':')));
Here is a solution with recursion:
var data = [];
function createJSON(input) {
var rows = input.split("\n");
for(var i = 0; i < rows.length; i++) {
data.push(createObject(rows[i].split(":")));
}
}
function createObject(array) {
if(array.length === 1) {
return array[0];
} else {
var obj = {};
obj[array[0]] = createObject(array.splice(1));
return obj;
}
}
createJSON("p\nq\nname:rawr:awesome");
console.log(data);

Categories

Resources