Reputation: 30739
I have been trying to create a tree structure as:
var result = {
email: {
schema: {
verified: 'email.verified',
email_address: 'email.email_address',
entity: {
schema: {
name: 'email.entity.name',
type: 'email.entity.type',
email: {
schema: {
verified: 'email.entity.email.verified',
email_address: 'email.entity.email.email_address'
}
}
}
}
}
}
};
From the array data as given below:
var schema = {
'paths': [
'email.email_address',
'email.entity.email.email_address',
'email.entity.email.verified',
'email.entity.type',
'email.entity.name',
'email.verified',
'created_at',
'contact_numbers'
]
}
You see that the output I expect has schema
property nested withing n
levels and that is not predictable. It depends on the value of the paths
like as in 'email.entity.email.email_address'
. You can split that with dot and seemingly each dot is replaced with schema
property in the output.
I am trying to use recursion, but I am not able to set that flow. Below is the code I have tried so far:
var schema = {
'paths': [
'email.email_address',
'email.entity.email.email_address',
'email.entity.email.verified',
'email.entity.type',
'email.entity.name',
'email.verified',
'created_at',
'contact_numbers'
]
}
var newSchema = {};
var key = 'email';
var existKeys = schema.paths.filter((path) => path.includes(key + '.'));
var requiredObject = {};
existKeys.forEach((existKey) => {
var splitKeys = existKey.split('.');
splitKeys.forEach((splitKey, index) => {
if (requiredObject[splitKey] && index + 1 === splitKeys.length) {
requiredObject[splitKey].schema = existKey;
} else {
requiredObject[splitKey] = {
'schema': {}
}
}
});
});
console.log(requiredObject);
Upvotes: 1
Views: 108
Reputation: 4184
Using 2 Array.reduce
you can achieve like below
var schema = {
'paths': [
'email.email_address',
'email.entity.email.email_address',
'email.entity.email.verified',
'email.entity.type',
'email.entity.name',
'email.verified',
'created_at',
'contact_numbers'
]
}
let res = schema.paths.reduce((o, d) => {
let keys = d.split('.')
keys.reduce((t, k, i) => {
t[k] = (i != keys.length - 1)
? (t[k] || { schema: {} })
: d
return t[k].schema
}, o)
return o
}, {})
console.log(res)
// for only email
console.log({ email: res.email })
Upvotes: 0
Reputation: 370619
I'd reduce
over the paths
array, using a helper function assignNested
which, given an outer object, a value, and a property array, uses the top property to create the schema
object and recursively call itself, until the array has only one item left, and the final value can be assigned:
var schema = {
'paths': [
'email.email_address',
'email.entity.email.email_address',
'email.entity.email.verified',
'email.entity.type',
'email.entity.name',
'email.verified',
'created_at',
'contact_numbers'
]
};
function assignNested(obj, val, props) {
if (props.length === 1) {
obj[props[0]] = val;
return;
}
const nextProp = props.shift();
if (!obj.schema) obj.schema = {};
if (!obj.schema[nextProp]) obj.schema[nextProp] = {};
assignNested(obj.schema[nextProp], val, props);
}
const fullResult = schema.paths.reduce((a, path) => {
const props = path.split('.');
assignNested(a, path, props);
return a;
}, {});
// fullResult contains the *full* structure,
// but if you only want the nested `email` part, then:
const result = {
email: {
schema: fullResult.schema.email
}
};
console.log(result);
Upvotes: 0
Reputation: 386519
You could reduce the paths and take for every found key a schema
property as well.
var schema = { paths: ['email.email_address', 'email.entity.email.email_address', 'email.entity.email.verified', 'email.entity.type', 'email.entity.name', 'email.verified', 'created_at', 'contact_numbers'] },
result = schema.paths
.filter(s => s.startsWith('email')) // or not or so, if so, maybe
.reduce((r, p) => {
var keys = p.split('.'),
last = keys.pop();
keys.reduce((o, k) => (o[k] = o[k] || { schema: {} }).schema, r)[last] = p;
return r;
}, {});
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Upvotes: 1