Recursive string parsing into object - javascript

Hello guys I'm trying to parse an array of strings into a custom structure:
var str = [
"country.UK.level.1",
"country.UK.level.2",
"country.US.level.1",
"country.UK.level.3"
];
Into something like:
var ordered = {
"country": [
{"UK" : {"level" : ["1", "2", "3"]}},
{"US" : {"level" : ["1","2"]}}
]
}
Notes:
Strings stored in the str array will not be sorted and the code should be robust against that.
Strings will follow the x.y.x.y... pattern, where x will be unique for that array and y can change. In my example country and level will always be the same as they represent the x pos.
This requires recursive approach as the strings stored in the str array, can be of any length. The longer the string the deeper nesting.

This should work for you if the last level of your object is an array:
var str = [
"country.UK.level.1",
"country.UK.level.2",
"country.US.level.1",
"country.UK.level.3"
];
var obj = {};
str.forEach(function(str){
var curr = obj;
var splitted = str.split('.');
var last = splitted.pop();
var beforeLast = splitted.pop();
splitted.forEach(function(sub){
if(!curr.hasOwnProperty(sub))
{
curr[sub] = {};
}
curr = curr[sub];
});
if(!curr[beforeLast]){
curr[beforeLast] = [];
}
curr[beforeLast].push(last);
})
console.log(obj);
JSFIDDLE.

This solution utilized a Array.prototype.forEach and Array.prototype.reduce.
var str = [
"country.UK.level.1",
"country.UK.level.2",
"country.US.level.1",
"country.UK.level.3"
],
ordered = {};
str.forEach(function (a) {
var aa = a.split('.'),
val = aa.pop(),
last = aa.length - 1;
aa.reduce(function (obj, pro, i) {
if (!(pro in obj)) {
obj[pro] = i === last ? [] : {};
}
return obj[pro];
}, ordered).push(val);
});
document.write('<pre>' + JSON.stringify(ordered, 0, 4) + '</pre>');

Related

Split array of string with multiple delimiters and store in separate arrays

I have a Javascript object like
Object = { "ratio1" : "12+45*36",
"ratio2" : "34+45*16",
"ratio3" : "17+25"}
I am trying to split the values like the values before + in one array and values after + in one array . so the output should be like
Array1= ["12" , "34" , "17"]
Array2 = ["45" , "36" , "45","16","25"].
To perform this I am iterating through the keys and getting the values first then I am again iterating through the values array I am splitting it using
ratioArray.split("+");
This gave me [[" 12" , "45*36"], [" 34", "45*16"], [" 17", "25"]]
Now again I have iterate through all the three arrays and split using second delimiter. Is there any efficient way to perform this so that I can reduce these many iterations
const ratios = {
"ratio1" : "12+45*36",
"ratio2" : "34+45*16",
"ratio3" : "17+25"
}
const nums = Object.keys(ratios)
.map(key => ratios[key]
.replace(/[+*]/g, '|')
.split('|')
)
const [ array1, array2, array3 ] = nums
document.querySelector('pre').innerText =
`array1 === [${array1}]\n` +
`array2 === [${array2}]\n` +
`array2 === [${array3}]\n`
<pre />
var Object = {
"ratio1": "12+45*36",
"ratio2": "34+45*16",
"ratio3": "17+25"
}
var Array1 = [],
Array2 = [],
temp;
for (var key in Object) {
temp = Object[key].split('+');
Array1.push(temp[0])
temp = temp[1].split('*')
for(var i = 0; i < temp.length; i++){
Array2.push(temp[i])
}
}
console.log('Array1:['+Array1[0]+','+Array1[1]+','+Array1[2]+']')
console.log('Array2:['+Array2[0]+','+Array2[1]+','+Array2[2]+','+Array2[3]+','+Array2[4]+']')
You can do something like this.
object = {
"ratio1": "12+45*36",
"ratio2": "34+45*16",
"ratio3": "17+25"
}
var array1 = [],
array2 = [];
for (var key in object) {
var _o = object[key].split("+");
array1.push(_o[0]);
_o[1].split("*").forEach(function(num) {
array2.push(num);
})
};
console.log("array 1", array1);
console.log("array 2", array2)

how can i transmission array to object with lodash?

I have an array like as below
var arr = [ 'type=A', 'day=45' ];
var trans = { 'type': 'A', 'day': 45 }
Please write easiest and most efficient way :)
You could split the string and check if the value isNaN for string or take the numerical value.
var array = [ 'type=A', 'day=45', 'bar=0' ],
object = Object.create(null);
array.forEach(function (a) {
var p = a.split('=');
object[p[0]] = isNaN(p[1]) ? p[1] : +p[1];
});
console.log(object);
The solution using Array.prototype.reduce() function:
var arr = [ 'type=A', 'day=45' ],
trans = arr.reduce(function(r, s){
var parts = s.split('=');
r[parts[0]] = isNaN(parts[1]) ? parts[1] : +parts[1];
return r;
}, {});
console.log(trans);
Iterate over each item in the array
Split on =
Add value to object, at key index
var arr = [ 'type=A', 'day=45' ];
var object = {};
for (var i = 0; i < arr.length; i++) {
var currentItem = arr[i].split('=');
var key = currentItem[0];
var value = currentItem[1];
object[key] = value;
}
console.log(object);
There's probably a million different ways to this, this way uses two different functions. the _.map() call runs on every element, splitting (and parsing) the element (if it matches a character regex). It then uses Lodash's .fromPairs function, which converts an array made up of 2 element arrays to return an object.
var arr = ['type=A', 'day=45'];
var obj = _.fromPairs(_.map(arr, function(item) {
var parts = item.split('=');
var digits = /^\d+$/;
if (digits.test(parts[1])) parts[1] = parseInt(parts[1]);
return parts;
}));
console.log(obj);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.4/lodash.min.js"></script>

Convert dot notation json

ive got a json object like this:
{
"c.employees": "222",
" c.arr[0].name": "thomas",
" c.arr[0].amount": 3,
}
I want to convert it to object like
{
c:{
employees:"222",
arr:[{name:thomas,amount:3}]
}
}
cant find any solution :/ The array is the problem
There's no short solution, you need to parse all keys and build the intermediate objects and arrays. As this isn't trivial, here's the code :
var input = {
"c.employees": "222",
" c.arr[0].name": "thomas",
" c.arr[0].amount": 3,
};
var output = {};
for (var key in input) {
var tokens = key.trim().split('.'),
obj = output;
for (var i=0; i<tokens.length-1; i++) {
var m = tokens[i].match(/^(\w+)\[(\d+)\]$/); // array ?
if (m) {
var arr = obj[m[1]];
if (!arr) arr = obj[m[1]] = [];
obj = arr[m[2]] = arr[m[2]]||{};
} else {
obj = obj[tokens[i]] = obj[tokens[i]]||{};
}
}
obj[tokens[i]] = input[key];
}
console.log(output);
demo (open the console)

Split array as per values in it

I have array like this
var aaa = [
[value1,value2],[0,0]],
[[value3,value4],[0,1]],
[[value5,value6],[1,0]],
[[value7,value8],[0,2]],
[[value9,value10],[1,1]],
[value11,value12],[2,0]]
];
I want to split this array into multiple arrays as per values [0,1], [0,2], etc.
I.e.
array1 = [[value1,value2],[value3,value4],[value7,value8]];
array2 = [[value5,value6],[value9,value10]];
array3 = [[value11,value12]];
How can I do this ?
Use this:
var aaa = [
[['value1','value2'],[0,1]],
[['value3','value4'],[0,2]],
[['value5','value6'],[1,0]],
[['value7','value8'],[0,3]],
[['value9','value10'],[1,1]],
[['value11','value12'],[2,0]]];
var result = {};
for (var i = 0; i < aaa.length; i += 1) {
if (!result[aaa[i][1][0]]) {
result[aaa[i][1][0]] = [];
}
result[aaa[i][1][0]].push(aaa[i][0]);
}
After that:
result[0]; //[[value1,value2],[value3,value4],[value7,value8]];
result[1]; //[[value5,value6],[value9,value10]];
result[2]; //[[value5,value6],[value9,value10]];
Supposing this :
[['value1','value2'],[0,1]]
In this example :
0 tell in which array the value must be stored.
1 tell in which cell of this array it must be stored.
This code would do the work :
var aaa = [
[['value1','value2'],[0,1]],
[['value3','value4'],[0,2]],
[['value5','value6'],[1,0]],
[['value7','value8'],[0,3]],
[['value9','value10'],[1,1]],
[['value11','value12'],[2,0]]
];
var arr_result = new Array();
for (var k in aaa) {
if (arr_result[aaa[k][1][0]] == undefined) {
arr_result[aaa[k][1][0]] = new Array();
}
arr_result[aaa[k][1][0]][aaa[k][1][1]] = aaa[k][0];
}
Warning : this could let empty cells, just as in this example, there is no [0,0] cell.

String to object in JS

I have a string as
string = "firstName:name1, lastName:last1";
now I need one object obj such that
obj = {firstName:name1, lastName:last1}
How can I do this in JS?
Actually, the best solution is using JSON:
Documentation
JSON.parse(text[, reviver]);
Examples:
1)
var myobj = JSON.parse('{ "hello":"world" }');
alert(myobj.hello); // 'world'
2)
var myobj = JSON.parse(JSON.stringify({
hello: "world"
});
alert(myobj.hello); // 'world'
3)
Passing a function to JSON
var obj = {
hello: "World",
sayHello: (function() {
console.log("I say Hello!");
}).toString()
};
var myobj = JSON.parse(JSON.stringify(obj));
myobj.sayHello = new Function("return ("+myobj.sayHello+")")();
myobj.sayHello();
Your string looks like a JSON string without the curly braces.
This should work then:
obj = eval('({' + str + '})');
WARNING: this introduces significant security holes such as XSS with untrusted data (data that is entered by the users of your application.)
If I'm understanding correctly:
var properties = string.split(', ');
var obj = {};
properties.forEach(function(property) {
var tup = property.split(':');
obj[tup[0]] = tup[1];
});
I'm assuming that the property name is to the left of the colon and the string value that it takes on is to the right.
Note that Array.forEach is JavaScript 1.6 -- you may want to use a toolkit for maximum compatibility.
This simple way...
var string = "{firstName:'name1', lastName:'last1'}";
eval('var obj='+string);
alert(obj.firstName);
output
name1
Since JSON.parse() method requires the Object keys to be enclosed within quotes for it to work correctly, we would first have to convert the string into a JSON formatted string before calling JSON.parse() method.
var obj = '{ firstName:"John", lastName:"Doe" }';
var jsonStr = obj.replace(/(\w+:)|(\w+ :)/g, function(matchedStr) {
return '"' + matchedStr.substring(0, matchedStr.length - 1) + '":';
});
obj = JSON.parse(jsonStr); //converts to a regular object
console.log(obj.firstName); // expected output: John
console.log(obj.lastName); // expected output: Doe
This would work even if the string has a complex object (like the following) and it would still convert correctly. Just make sure that the string itself is enclosed within single quotes.
var strObj = '{ name:"John Doe", age:33, favorites:{ sports:["hoops", "baseball"], movies:["star wars", "taxi driver"] }}';
var jsonStr = strObj.replace(/(\w+:)|(\w+ :)/g, function(s) {
return '"' + s.substring(0, s.length-1) + '":';
});
var obj = JSON.parse(jsonStr);
console.log(obj.favorites.movies[0]); // expected output: star wars
If you have a string like foo: 1, bar: 2 you can convert it to a valid obj with:
str
.split(',')
.map(x => x.split(':').map(y => y.trim()))
.reduce((a, x) => {
a[x[0]] = x[1];
return a;
}, {});
Thanks to niggler in #javascript for that.
Update with explanations:
const obj = 'foo: 1, bar: 2'
.split(',') // split into ['foo: 1', 'bar: 2']
.map(keyVal => { // go over each keyVal value in that array
return keyVal
.split(':') // split into ['foo', '1'] and on the next loop ['bar', '2']
.map(_ => _.trim()) // loop over each value in each array and make sure it doesn't have trailing whitespace, the _ is irrelavent because i'm too lazy to think of a good var name for this
})
.reduce((accumulator, currentValue) => { // reduce() takes a func and a beginning object, we're making a fresh object
accumulator[currentValue[0]] = currentValue[1]
// accumulator starts at the beginning obj, in our case {}, and "accumulates" values to it
// since reduce() works like map() in the sense it iterates over an array, and it can be chained upon things like map(),
// first time through it would say "okay accumulator, accumulate currentValue[0] (which is 'foo') = currentValue[1] (which is '1')
// so first time reduce runs, it starts with empty object {} and assigns {foo: '1'} to it
// second time through, it "accumulates" {bar: '2'} to it. so now we have {foo: '1', bar: '2'}
return accumulator
}, {}) // when there are no more things in the array to iterate over, it returns the accumulated stuff
console.log(obj)
Confusing MDN docs:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/Reduce
Demo: http://jsbin.com/hiduhijevu/edit?js,console
Function:
const str2obj = str => {
return str
.split(',')
.map(keyVal => {
return keyVal
.split(':')
.map(_ => _.trim())
})
.reduce((accumulator, currentValue) => {
accumulator[currentValue[0]] = currentValue[1]
return accumulator
}, {})
}
console.log(str2obj('foo: 1, bar: 2')) // see? works!
You need use JSON.parse() for convert String into a Object:
var obj = JSON.parse('{ "firstName":"name1", "lastName": "last1" }');
if you're using JQuery:
var obj = jQuery.parseJSON('{"path":"/img/filename.jpg"}');
console.log(obj.path); // will print /img/filename.jpg
REMEMBER: eval is evil! :D
I implemented a solution in a few lines of code which works quite reliably.
Having an HTML element like this where I want to pass custom options:
<div class="my-element"
data-options="background-color: #dadada; custom-key: custom-value;">
</div>
a function parses the custom options and return an object to use that somewhere:
function readCustomOptions($elem){
var i, len, option, options, optionsObject = {};
options = $elem.data('options');
options = (options || '').replace(/\s/g,'').split(';');
for (i = 0, len = options.length - 1; i < len; i++){
option = options[i].split(':');
optionsObject[option[0]] = option[1];
}
return optionsObject;
}
console.log(readCustomOptions($('.my-element')));
In your case, The short and beautiful code
Object.fromEntries(str.split(',').map(i => i.split(':')));
I'm using JSON5, and it's works pretty well.
The good part is it contains no eval and no new Function, very safe to use.
string = "firstName:name1, lastName:last1";
This will work:
var fields = string.split(', '),
fieldObject = {};
if( typeof fields === 'object') ){
fields.each(function(field) {
var c = property.split(':');
fieldObject[c[0]] = c[1];
});
}
However it's not efficient. What happens when you have something like this:
string = "firstName:name1, lastName:last1, profileUrl:http://localhost/site/profile/1";
split() will split 'http'. So i suggest you use a special delimiter like pipe
string = "firstName|name1, lastName|last1";
var fields = string.split(', '),
fieldObject = {};
if( typeof fields === 'object') ){
fields.each(function(field) {
var c = property.split('|');
fieldObject[c[0]] = c[1];
});
}
const text = '{"name":"John", "age":30, "city":"New York"}';
const myArr = JSON.parse(text);
document.getElementById("demo").innerHTML = myArr.name;
This is universal code , no matter how your input is long but in same schema if there is : separator :)
var string = "firstName:name1, lastName:last1";
var pass = string.replace(',',':');
var arr = pass.split(':');
var empty = {};
arr.forEach(function(el,i){
var b = i + 1, c = b/2, e = c.toString();
if(e.indexOf('.') != -1 ) {
empty[el] = arr[i+1];
}
});
console.log(empty)
Here is my approach to handle some edge cases like having whitespaces and other primitive types as values
const str = " c:234 , d:sdfg ,e: true, f:null, g: undefined, h:name ";
const strToObj = str
.trim()
.split(",")
.reduce((acc, item) => {
const [key, val = ""] = item.trim().split(":");
let newVal = val.trim();
if (newVal == "null") {
newVal = null;
} else if (newVal == "undefined") {
newVal = void 0;
} else if (!Number.isNaN(Number(newVal))) {
newVal = Number(newVal);
}else if (newVal == "true" || newVal == "false") {
newVal = Boolean(newVal);
}
return { ...acc, [key.trim()]: newVal };
}, {});
In your case
var KeyVal = string.split(", ");
var obj = {};
var i;
for (i in KeyVal) {
KeyVal[i] = KeyVal[i].split(":");
obj[eval(KeyVal[i][0])] = eval(KeyVal[i][1]);
}
var stringExample = "firstName:name1, lastName:last1 | firstName:name2, lastName:last2";
var initial_arr_objects = stringExample.split("|");
var objects =[];
initial_arr_objects.map((e) => {
var string = e;
var fields = string.split(','),fieldObject = {};
if( typeof fields === 'object') {
fields.forEach(function(field) {
var c = field.split(':');
fieldObject[c[0]] = c[1]; //use parseInt if integer wanted
});
}
console.log(fieldObject)
objects.push(fieldObject);
});
"objects" array will have all the objects
I know this is an old post but didn't see the correct answer for the question.
var jsonStrig = '{';
var items = string.split(',');
for (var i = 0; i < items.length; i++) {
var current = items[i].split(':');
jsonStrig += '"' + current[0] + '":"' + current[1] + '",';
}
jsonStrig = jsonStrig.substr(0, jsonStrig.length - 1);
jsonStrig += '}';
var obj = JSON.parse(jsonStrig);
console.log(obj.firstName, obj.lastName);
Now you can use obj.firstName and obj.lastName to get the values as you could do normally with an object.
You don't have to always convert to JSON
So here "person begin as a string!" Finally, "person is converted to object", no necessarily to JSON.
function strToObj(e){if(typeof e=="string"){ let obj=new Function("return" +e); try{return obj()}catch{console.log("Fix, String no allowed to object")}}else{console.log("it is not a string") } };
//Example, person is a string
let person='{firstName:"John", lastName:"Doe", id: 55, fullName:function(){return this.firstName+" "+this.lastName} }';
console.log(strToObj(person));
And it run functions internal to the object without major issues if it is called:
person=strToObj(person); console.log(person.fullName())
Simply, string = "firstName:name1, lastName:last1";
let string = "firstName:name1, lastName:last1";
let object= strToObj("{"+string+"}");
console.log(object)

Categories

Resources