JavaScript How to convert a string into a nested object - javascript

I have a response string like this:
|||COVID HPI^^^FEVER^^^Low Grade
|||COVID HPI^^^FEVER^^^Continuous
|||COVID HPI^^^RHINORRHEA/SNEEZING^^^No
|||GENERAL EXAM^^^CL^^^Conscious
|||GENERAL EXAM^^^ORIENTED^^^Yes
And i want to convert it into something like this:
{
"COVID HPI": [
{
"FEVER": "Low Grade, Continuous",
"RHINORRHEA/SNEEZING": "Yes"
}
],
"GENERAL EXAM": [
{
"CL": "Conscious",
"ORIENTED": "Yes"
}
]
}
I am not able to go beyond this without an ugly code:
const na = [];
fetch('http://localhost/test/json/newdata.json')
.then(response => {
let vv = response.json();
return vv;
})
.then(function(data){
console.log(data[0]['tRxVal'])
let nav = data[0]['tRxVal'].slice(3).split('|||');
let nbv = nav.map(function(item,i){
return item.split('^^^');
});
//console.log(nbv);
nbv.forEach(function(v,i){
if(!na.includes(v[0])){
na.push(v[0]);
}
})
console.log(na)
})
.catch(err => {
// handle errors
});
Can someone please help me with this
Thanks

You should try to use the split function.
You could do a first split on the string for "|||", after that you could split all the resulting strings for "^^^", so that you can divide keys and values.
Something like that (take it as pseudocode)
let strings = data.split("|||");
for (string in strings){
let objectKeyValue = string.split("^^^");
let object = objectKeyValue[0];
let key = objectKeyValue[1];
let value = objectKeyValue[2];
}
from here, compose your object and you're good to go.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/split

Split by ||| to get each row, and then split each row by ^^^. Then, you can think of each "row" like this: <topLevelCategory>^^^<subCategory>^^^<subCategoryAnswer>. Use this mental model of each row to build your object around.
const string = `|||COVID HPI^^^FEVER^^^Low Grade
|||COVID HPI^^^FEVER^^^Continuous
|||COVID HPI^^^RHINORRHEA/SNEEZING^^^No
|||GENERAL EXAM^^^CL^^^Conscious
|||GENERAL EXAM^^^ORIENTED^^^Yes`;
function stringToObj(str) {
const branches = str.split('|||');
const obj = {};
branches.forEach((branch) => {
const leaves = branch.split('^^^');
const [top, sub, answer] = leaves;
if (top) {
if (!obj[top]) obj[top] = {};
const trimmedAnswer = answer.trim();
const curr = obj[top][sub];
if (curr) {
obj[top][sub] = `${curr}, ${trimmedAnswer}`;
} else {
obj[top][sub] = answer.trim();
}
}
});
return obj;
}
console.log(stringToObj(string));

Related

How do I convert a string to a dictionary in javascript?

I have a string
var str = "1:6,5,2,2:3";
I want to convert this str into a js dictionary such that:
var dict = {1:"6,5,2",
2:"3"};
so that I can fetch the values by their respective key index. How do I convert it?
I had tried this code to store the splitted values into an array:
var pages = "1:6,5,2,2:3";
var numbers = [];
if (pages.includes(',')) {
page_nos = pages.split(',');
for (var i = 0; i < page_nos.length; i++) {
if (page_nos[i].includes(':')) {
var n = page_nos[i].split(':');
numbers.push(n[1]);
} else {
numbers.push(page_nos[i]);
}
}
} else {
page_nos = pages.split(':');
numbers.push(page_nos[1])
};
console.log('numbers: ', numbers);
But it's incorrect, as without dictionary it's impossible to know what value belongs to which index
If you cannot make your input string a proper JSON or another easily parsable format in the first place, this answers your question:
const str = "1:6,5,2,2:3";
const obj = str.split(/,(?=\d+:)/).reduce((accu, part) => {
const [k, v] = part.split(':', 2);
accu[k] = v;
return accu;
}, {});
console.log(obj);
Cut the string at all commas that are followed by digits and a colon. Each part has a key in front of a colon and a value after it, which should be stuffed in an object in this format.
No mutations solution.
const str = "1:6,5,2,2:3";
const dict = str
.split(/(\d+:.*)(?=\d+:)/g)
.reduce((t, c) => {
const [key, value] = c.replace(/,$/, "").split(/:/);
return { ...t, [key]: value }
});
console.log(dict);
if you consider not using regular expression, you might try this as well.
to take out a dict (Object) from that string, this will do.
var pages = "1:6,5,2,2:3";
function stringToObject(str) {
var page_object = {};
var last_object;
str.split(",").forEach((item) => {
if (item.includes(":")) {
page_object[item.split(":")[0]] = item.split(":")[1];
last_object = item.split(":")[0];
} else {
page_object[last_object] += `,${item}`;
}
});
return page_object;
}
console.log(stringToObject(pages))
Presented below may be one possible solution to achieve the desired objective.
NOTE:
In lieu of var the code uses either let or const as applicable.
Code Snippet
const pages = "1:6,5,2,2:3";
const resObj = {};
let page_nos, k;
if (pages.includes(',')) {
page_nos = pages.split(',');
for (let i = 0; i < page_nos.length; i++) {
if (page_nos[i].includes(':')) {
let n = page_nos[i].split(':');
k = n[0];
resObj[k] = n[1].toString();
} else {
resObj[k] += ", " + page_nos[i].toString();
}
}
} else {
page_nos = pages.split(':');
resObj[page_nos[0]] = [page_nos[1]]
numbers.push(page_nos[1])
};
console.log('result object: ', resObj);
This code essentially fixes the code given in the question. It is self-explanatory and any specific information required may be added based on questions in comments.
You could take nested splitring for entries and get an object from it.
const
str = "1:6,5,2,2:3",
result = Object.fromEntries(str
.split(/,(?=[^,]*:)/)
.map(s => s.split(':'))
);
console.log(result);

Parsing string with special character and returning the output

I know its a pretty simple question, but to anyone who is new to Javascript this can be interesting.
Is there any fastest way to parse this string and get the color for the fruit like shown below :
var fruitAndColors = "APPLE=RED&GUAVA=GREEN&STRAWBERRY=RED&BANANA=yellow&ORANGE=orange"
var applecolor = getColor("APPLE") // RED
var bananaColor = getColor("BANANA") //yellow
Here is a regex match approach:
function getColor(fruitAndColors, fruit) {
return fruitAndColors.match(new RegExp("\\b" + fruit + "=([^&]+)"))[1];
}
var fruitAndColors = "APPLE=RED&GUAVA=GREEN&STRAWBERRY=RED&BANANA=yellow&ORANGE=orange"
console.log(getColor(fruitAndColors, "APPLE")); // RED
console.log(getColor(fruitAndColors, "BANANA")); //yellow
For the case of searching for APPLE we use the following regex pattern:
\bAPPLE=([^&]+)
This places the key (the color) in the first capture group, which the helper function then returns.
Regex will probably be the best bet for this however it is definitely not my strong-suit. That said, here's what I came up with just some Javascript:
var fruitAndColors =
'APPLE=RED&GUAVA=GREEN&STRAWBERRY=RED&BANANA=yellow&ORANGE=orange';
const getColor = (key) => {
const entries = fruitAndColors.split('&').reduce((acc, val) => {
const [fruit, color] = val.split('=');
acc[fruit] = color;
return acc;
}, {});
return entries[key];
};
var appleColor = getColor('APPLE'); // RED
var bananaColor = getColor('BANANA'); //yellow
A little class that handle that kind of url parse
class UrlParse {
#objects;
constructor(uri) {
this.uri = uri
this.objects = {}
this.parse()
}
parse() {
let arr = this.uri.split('&')
for (let a of arr) {
let arr = a.split(/\=/)
this.objects[arr[0]] = arr[1]
}
}
getName(name) {
return this.objects[name]
}
}
var fruitAndColors = "APPLE=RED&GUAVA=GREEN&STRAWBERRY=RED&BANANA=yellow&ORANGE=orange"
let p = new UrlParse(fruitAndColors)
console.log(p.getName('BANANA'))
You can use a regular expression passing in the fruit, and returning the first match.
const fruitAndColors = 'APPLE=RED&GUAVA=GREEN&STRAWBERRY=RED&BANANA=yellow&ORANGE=orange';
console.log(getColor('APPLE', fruitAndColors));
console.log(getColor('GUAVA', fruitAndColors));
console.log(getColor('STRAWBERRY', fruitAndColors));
console.log(getColor('BANANA', fruitAndColors));
console.log(getColor('ORANGE', fruitAndColors));
function getColor(fruit, fruitAndColors) {
const regex = new RegExp(`${fruit}=([A-Za-z]+)`);
return fruitAndColors.match(regex)[1];
}
Why don't we just use a map instead of parsing it with regex. I think that would be more efficient.
const str = "APPLE=RED&GUAVA=GREEN&STRAWBERRY=RED&BANANA=yellow&ORANGE=orange";
const fruitColorArray = str.split("&").map((value) => value.split("="));
const fruitColorMap = new Map(fruitColorArray);
function getColor(fruit) {
return fruitColorMap.get(fruit);
}
const applecolor = getColor("APPLE"); // RED
const bananaColor = getColor("BANANA"); //yellow
console.log(applecolor, bananaColor);

texts in array converts to objects

I am using node to convert an array to object, I have an array looks like this
[
'items[0].book=Book1',
'items[0].color=Red',
'items[0].bookCode=#1',
'items[1].book=Book2',
'items[1].color=Yellow',
'items[1].bookCode=#2',
'items[2].book=Book3',
'items[2].color=Blue',
'items[2].bookCode=#3',
...
]
I am trying to convert it to be objets in one array
items:[
{
book: "Book1",
color: "Red",
bookCode: "#1"
},
{
book: "Book2",
color: "Yellow",
bookCode: "#2"
},
...
]
I found it is easy to conver it uses a 3rd party lib like setKeypath/set,
const obj = {};
const arr = [items......(like above)]
arr.forEach((val => {
if (val.startsWith('items[')) {
const splitWord = item.split('=');
setKeypath(obj, splitWord[0], splitWord[1]);
}
});
I am seeking a way if it can be done the same output with es6, so I don't really need a library. Thanks
const items = [
"items[0].book=Book1",
"items[0].color=Red",
"items[0].bookCode=#1",
"items[1].book=Book2",
"items[1].color=Yellow",
"items[1].bookCode=#2",
"items[2].book=Book3",
"items[2].color=Blue",
"items[2].bookCode=#3"
];
let res = [];
let currId = "";
let currItem = null;
for (let i = 0; i < items.length; i++) {
let parts = items[i].split(".");
if (currId!==parts[0] && currItem) { //new item
res.push(currItem)
currId = parts[0];
}
if (!currItem)
currItem = {};
let keyValue = parts[1].split("=");
currItem[keyValue[0]] = keyValue[1]
}
console.log({items: res})
You may first find all values by regex, and insert the attribute to each corresponding element one by one. This approach works for whatever ordering the array is, and whatever attributes there are, as long as each element follow the same pattern.
let items = [
"items[1].bookCode=#2",
"items[0].book=Book1",
"items[0].bookCode=#1",
"items[1].book=Book2",
"items[2].bookCode=#3",
"items[1].color=Yellow",
"items[2].book=Book3",
"items[2].color=Blue",
"items[0].color=Red",
"items[4].test=test!"
];
let indexPattern = /\[(\d*)\]/;
let attrPattern = /\.(.*)=/;
let valuePattern = /=(.*)/;
let obj = Object.values(
items.reduce((obj, element) => {
let index = element.match(indexPattern)[1];
let attr = element.match(attrPattern)[1];
let value = element.match(valuePattern)[1];
if (!obj.hasOwnProperty(index)) obj[index] = {};
obj[index][attr] = value;
return obj;
}, {})
);
console.log(obj);
[
'items[0].book=Book1',
'items[0].color=Red',
'items[0].bookCode=#1',
'items[1].book=Book2',
'items[1].color=Yellow',
'items[1].bookCode=#2',
'items[2].book=Book3',
'items[2].color=Blue',
'items[2].bookCode=#3',
].reduce((acc, str) => {
const index = Number(str.slice(str.indexOf('[') + 1, str.indexOf(']')));
if (!acc[index]) {
acc[index] = {};
}
const entry = [str.slice(str.indexOf('.') + 1, str.indexOf('=')), str.slice(str.indexOf('=') + 1)];
acc[index][entry[0]] = entry[1];
return acc;
}, []);
Here I pick apart the string you're given based on the consistent format, grab the index, key, and value, and then just use Array#reduce to do the work of putting the array together.
Documentation:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/reduce
I think a smattering of regex would do the trick:
const ar = [
'items[0].book=Book1',
'items[0].color=Red',
'items[0].bookCode=#1',
'items[1].book=Book2',
'items[1].color=Yellow',
'items[1].bookCode=#2',
'items[2].book=Book3',
'items[2].color=Blue',
'items[2].bookCode=#3'
]
const result = [];
ar.forEach(item => {
const index = parseInt(item.match(/\[([0-9]+)\]/)[1]);
const params = item.split(".")[1].split("=");
if(!result[index])
result[index] = {}
result[index][params[0]] = params[1];
})
console.log(result)
Note that item.match(/\[([0-9]+)\]/) matches the number inside your brackets. match returns an array where 1 is the index of the actual value between the brackets.

JavaScript convert string to object contains ":"

I have the following string var xx = "website:https://google.com"; I'm trying to convert to dictionary {website:"https://google.com"} usually I use str.split(":") but here I have multi : I can use replace function but what is the best way to do that ?
const strToDictionary = kColonV => {
const tmpArray = kColonV.split(':')
const k = tmpArray.shift()
const v = tmpArray.join(':')
return {[k]:v}
}
var xx = "website:https://google.com";
strToDictionary(xx) // Object { website: "https://google.com" }
Or, perhaps just:
const toDictonary = str => { return {[str.split(':')[0]]:str.substr(str.indexOf(':')+1)} }
toDictionary(xx) // Object { website: "https://google.com" }
There's a lot of ways you could phrase this.
class Dictionary extends Object {};
const kvToDict = str => Dictionary.assign( // No need to do this, but it's interesting to explore the language.
new Dictionary(),
{[str.slice(0, str.indexOf(':'))]:str.slice(str.indexOf(':')+1)}
)
const kvDict = kvToDict("website:https://google.com")
console.log(kvDict.constructor, kvDict) // Dictionary(), { website: "https://google.com" }
I like this one:
const kvToObj = str => Object.assign(
{},
{[str.slice(0, str.indexOf(':'))]:str.slice(str.indexOf(':')+1)}
)
kvToObj("website:https://google.com") // Object { website: "https://google.com" }
You can split on the first occurrence of :.
var xx = "website:https://google.com";
xx = xx.split(/:(.+)/);
var dictionary = {[xx[0]]:xx[1]};
console.log(dictionary);

typescript : logic to covert string array into custom object

Here is my requirement. I was able to achieve to some level in java but we need to move it to typescript (client side).
Note: The below input is for example purpose and may vary dynamically.
Input
var input = ["a.name", "a.type", "b.city.name" , "b.city.zip", "b.desc","c"];
We need to create an utility function that takes above input and returns output as below.
Output:
Should be string not an object or anything else.
"{ a { name, type }, b { city {name, zip } , desc }, c }"
any help is much appreciated.
I don't see that typescript plays any role in your question, but here's a solution for constructing the string you requested. I first turn the array into an object with those properties, then have a function which can turn an object into a string formatted like you have
const input = ["a.name", "a.type", "b.city.name" , "b.city.zip", "b.desc","c"];
const arrayToObject = (arr) => {
return arr.reduce((result, val) => {
const path = val.split('.');
let obj = result;
path.forEach(key => {
obj[key] = obj[key] || {};
obj = obj[key];
});
return result;
}, {});
}
const objectToString = (obj, name = '') => {
const keys = Object.keys(obj);
if (keys.length === 0) {
return name;
}
return `${name} { ${keys.map(k => objectToString(obj[k], k)).join(', ')} }`;
}
const arrayToString = arr => objectToString(arrayToObject(arr));
console.log(arrayToString(input));
Here's another variation. Trick is to parse the strings recursively and store the intermediate results in an Object.
function dotStringToObject(remainder, parent) {
if (remainder.indexOf('.') === -1) {
return parent[remainder] = true
} else {
var subs = remainder.split('.');
dotStringToObject(subs.slice(1).join('.'), (parent[subs[0]] || (parent[subs[0]] = {})))
}
}
var output = {};
["a.name", "a.type", "b.city.name" , "b.city.zip", "b.desc","c"].forEach(function(entry) {
dotStringToObject(entry, output)
});
var res = JSON.stringify(output).replace(/\"/gi, ' ').replace(/\:|true/gi, '').replace(/\s,\s/gi, ', ');
console.log(res)
// Prints: { a { name, type }, b { city { name, zip }, desc }, c }
You could do something like this:
var input = ["a.name", "a.type", "b.city.name" , "b.city.zip", "b.desc","c"];
var output = {};
for(var i =0; i < input.length; i+=2){
output[String.fromCharCode(i+97)] = {};
output[String.fromCharCode(i+97)].name = input[i];
output[String.fromCharCode(i+97)].type = input[i+1];
}
console.log(JSON.stringify(output));

Categories