create nested object from string JavaScript - javascript

I have a string like this:
let user = "req.user.role"
is there any way to convert this as nested objects for using in another value like this?
let converted_string = req.user.role
I know I can split the user with user.split(".")
my imagination :
let user = "req.user.role".split(".")
let converted_string = user[0].user[1].user[2]
I found the nearest answer related to my question : Create nested object from query string in Javascript

Try this
let user = "req.user.role";
let userObj = user.split('.').reduceRight((obj, next) => ({
[next]: obj
}), {});
console.log(userObj);
Or this, for old browsers
var user = "req.user.role";
var userArray = user.split('.'), userObj = {}, temp = userObj;
for (var i = 0; i < userArray.length; i++) {
temp = temp[userArray[i]] = {};
}
console.log(userObj);

The function getvalue() will return the nested property of a given global variable:
var user="req.user.role";
var req={user:{role:"admin"}};
function getvalue(str){
return str.split('.').reduce((r,c,i)=>i?r[c]:window[c], '');
}
console.log(getvalue(user));

I'll take my shot at this:
let user = "req.user.role"
const trav = (str, o) => {
const m = str.split('.')
let res = undefined
let i = 0
while (i < m.length) {
res = (res || o)[m[i]]
if (!res) break
i++
}
return res
}
const val = trav(user, {
req: {
user: {
role: "admin"
}
}
})
console.log(val)
this function will traversed the passed in object for the entire length of the provided string.split "." list returning either a value or undefined.

You can do it like this:
let userSplitted = "req.user.role".split('.');
let obj, o = obj = {};
userSplitted.forEach(key=>{o=o[key]={}});

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);

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.

what is the best way to extract variables with '=' from a string in javascript

I want to extract the variables names from a string like this: "foo=valor bar=second", and so on.
To return:
{
foo: "valor",
bar: "second",
...
}
You can use Regex Look Aheads to check for a variable name that is preceded by an = symbol
var str = "foo=valor bar=second";
var varRegex = /\w+(?=(\s)*(\=))/g;
var valueRegex = /(?<=(\=)[\s'"]*)\w+/g;
var varArr = str.match(varRegex);
var valueArr = str.match(valueRegex);
console.log(valueArr);
let obj = {};
for(let i in varArr) {
obj[varArr[i]] = valueArr[i];
}
console.log(obj);
var str = "foo=valor,bar=second";
var obj = {};
str.split(",").forEach(
function(item){
if(item){
var vars = item.split("=");
obj[vars[0]] = vars[1]
}
});
console.log(obj)
Different approach from the previous answer: You can split the string on spaces and then map the result array, splitting on the equal sign to create your object (left side is property, right side is value)
If you need it your specific format you can reduce it to convert the array into one big object with all the values
let a = "foo=valor bar=second"
console.log(a.split(' ').map((i,v) => { return JSON.parse(`{"${i.split('=')[0]}": "${i.split('=')[1]}"}`);}))
let b = a.split(' ').map((i,v) => { return JSON.parse(`{"${i.split('=')[0]}": "${i.split('=')[1]}"}`);})
console.log(b.reduce(function(acc, x) {
for (var key in x) acc[key] = x[key];
return acc;
}));
Not necessarily the quickest answer (in terms of speed of submission), but less regular expressions to maintain and less variables to store.
function toJSON(str) {
const regex = /(\w+)\=(\w+)\s*/g;
let result = {};
let match;
while (match = regex.exec(str)) {
result[match[1]] = match[2];
}
return result;
}
console.log(toJSON("foo=valor bar=second"));

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));

javascript copy object value from "schema" object

here is the situation. I got a an object contain lot of information, for example
var a = {
one:"foo",
two:"bar"
}
and now I want to provide and other object contained specify key. for example
var schema = {
two:""
}
then just create a new object base on key of schema
here , I would like to use lodash / moutjs or any lib
sorry for poor eng
With lodash you can _.pick() the schema _.keys() from the originalObj (the one you named a):
const originalObj = { one: "foo", two: "bar" }
const schema = { two: "" }
const result = _.pick(originalObj, _.keys(schema))
console.log(result)
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.js"></script>
If you want pure JS, you can reduce the schema Object.keys():
const originalObj = { one: "foo", two: "bar" }
const schema = { two: "" }
const result = Object.keys(schema)
.reduce((obj, key) =>
originalObj.hasOwnProperty(key) ? { ...obj, [key]: originalObj[key] } : obj
, {})
console.log(result)
You don't need a library for a that simple operation. Here's a working code:
var copyObject = function(origin, keys) {
var destination = {};
for (var i = keys.length - 1; i >= 0; i--) {
if(origin.hasOwnProperty(keys[i])) {
destination[keys[i]] = origin[keys[i]];
}
};
return destination;
};
var a = {
one:"foo",
two:"bar"
};
var schema = copyObject(a, ['two']);
I don't sure that I understood you correctly. But, for example, you can use pick in underscore.
var a = {
one:"foo",
two:"bar"
}
var schema = _.pick(a, "two"); // returns {two: "foo")
Note, that also working in lodash.
var copyObject = function(origin, keys) {
var destination = {};
for (var i = keys.length - 1; i >= 0; i--) {
if(origin.hasOwnProperty(keys[i])) {
destination[keys[i]] = origin[keys[i]];
}
};
return destination;
};
var a = {
one:"foo",
two:"bar"
};
var schema = copyObject(a, ['two']);

Categories