Create an object with multiple keys that don't exist at once - javascript

How do you create a nested object with multiple keys that don't exist? Instead of creating them one by one.
For example:
const state = {};
state [a][b][c] = 5;
How do you do this instead of:
state[a] = {};
state[a][b]={};
state[a][b][c] = 5;
I want to do this because state[a][b] may have others keys in it and I don't want to delete them. I only want to change the c key. But if there is no other key, then create it like this.
So state could also be:
state {
a: {
b: {
x: 20,
}
}
}

You can't do that. The only way is create a loop and then assign one by one:
function set(state, path, value) {
var pList = path.split('.');
var len = pList.length;
for (var i = 0; i < len - 1; i++) {
var elem = pList[i];
if (!state[elem]) state[elem] = {}
state = state[elem];
}
state[pList[len - 1]] = value;
return state;
}
const state = {};
set(state, 'a.b.c', 5);
console.log(state);

You could use hasOwnProperty in this way:
if (!state.hasOwnProperty(a)) state[a] = {};
if (!state[a].hasOwnProperty(b)) state[a][b] = {};
if (!state[a][b].hasOwnProperty(c)) state[a][b][c] = {};
state[a][b][c] = 5;

Is this correct?
const obj = { "a" : { "b" : { "c" : 5 } } };
console.log( obj.a.b.c );

Related

JavaScript: Convert dot notation string to array [duplicate]

I'm trying to create a JS object dynamically providing a key and a value. The key is in dot notation, so if a string like car.model.color is provided the generated object would be:
{
car: {
model: {
color: value;
}
}
}
The problem has a trivial solution if the key provided is a simple property, but i'm struggling to make it work for composed keys.
My code:
function (key, value) {
var object = {};
var arr = key.split('.');
for(var i = 0; i < arr.length; i++) {
object = object[arr[i]] = {};
}
object[arr[arr.length-1]] = value;
return object;
}
your slightly modified code
function f(key, value) {
var result = object = {};
var arr = key.split('.');
for(var i = 0; i < arr.length-1; i++) {
object = object[arr[i]] = {};
}
object[arr[arr.length-1]] = value;
return result;
}
In the loop you should set all of the props but the last one.
Next set the final property and all set.
If you're using lodash you could use _.set(object, path, value)
const obj = {}
_.set(obj, "car.model.color", "my value")
console.log(obj)
<script src="https://cdn.jsdelivr.net/npm/lodash#4.17.15/lodash.min.js"></script>
Use namespace pattern, like the one Addy Osmani shows: http://addyosmani.com/blog/essential-js-namespacing/
Here's the code, pasted for convenience, all credit goes to Addy:
// top-level namespace being assigned an object literal
var myApp = myApp || {};
// a convenience function for parsing string namespaces and
// automatically generating nested namespaces
function extend( ns, ns_string ) {
var parts = ns_string.split('.'),
parent = ns,
pl, i;
if (parts[0] == "myApp") {
parts = parts.slice(1);
}
pl = parts.length;
for (i = 0; i < pl; i++) {
//create a property if it doesnt exist
if (typeof parent[parts[i]] == 'undefined') {
parent[parts[i]] = {};
}
parent = parent[parts[i]];
}
return parent;
}
// sample usage:
// extend myApp with a deeply nested namespace
var mod = extend(myApp, 'myApp.modules.module2');
function strToObj(str, val) {
var i, obj = {}, strarr = str.split(".");
var x = obj;
for(i=0;i<strarr.length-1;i++) {
x = x[strarr[i]] = {};
}
x[strarr[i]] = val;
return obj;
}
usage: console.log(strToObj("car.model.color","value"));
I would use a recursive method.
var createObject = function(key, value) {
var obj = {};
var parts = key.split('.');
if(parts.length == 1) {
obj[parts[0]] = value;
} else if(parts.length > 1) {
// concat all but the first part of the key
var remainingParts = parts.slice(1,parts.length).join('.');
obj[parts[0]] = createObject(remainingParts, value);
}
return obj;
};
var simple = createObject('simple', 'value1');
var complex = createObject('more.complex.test', 'value2');
console.log(simple);
console.log(complex);
(check the console for the output)
Here's a recursive approach to the problem:
const strToObj = (parts, val) => {
if (!Array.isArray(parts)) {
parts = parts.split(".");
}
if (!parts.length) {
return val;
}
return {
[parts.shift()]: strToObj(parts, val)
};
}

Nested Object Loop in JS

I'm trying to add a series of values to a nested object, having some trouble with the loop in the following code. Any help would be really appreciated.
let settings = {};
function write(id, values) {
if(!settings[id]) settings[id] = {};
for(var x = 0; x < Object.keys(values).length; x ++) {
settings[id][values[x]] = values[values[x]];
}
}
//example
write('example', {'prop1': 5, 'prop2': 10});
You're attempting to index the object values with x, which is a number. To loop through the keys of your object you can use a for...in loop:
function write(id, values) {
if(!settings[id]) settings[id] = {};
for(const key in values) {
settings[id][key] = values[key];
}
}
Another approach would be to use object destructuring:
function write(id, values) {
settings[id] = { ...(settings[id] || {}), ...values };
}
values is an object. Accessing values[x] will return undefined.
You have to access it with the correct keys in that object as below.
let settings = {};
function write(id, values) {
if (!settings[id]) settings[id] = {};
const keys = Object.keys(values);
for (var x = 0; x < keys.length; x++) {
settings[id][keys[x]] = values[keys[x]];
}
console.log(settings)
}
//example
write('example', { 'prop1': 5, 'prop2': 10 });
try to keep the Object.keys(values) return in another variable and use it to assign value in setting like this
function write(id, values) {
if(!settings[id]) settings[id] = {};
const key = Object.keys(values)
for(var x = 0; x < key.length; x ++) {
settings[id][key[x]] = values[key[x]];
}
}

Create an object based on file path string

Given the path "documents/settings/user"
How can this be made into a nested object
Result
{
documents : {
settings : {
user : {}
}
}
}
I can't think of how to reference each previous path
var dir = {};
var paths = "documents/settings/user".split('/')
for (var i = 0; i < paths.length; i++) {
var path = paths[i];
if(i === 0)
dir[path] = {};
//else
//dir[path[i-?]] = {};
}
This is actually done quite easily with .reduce().
var dir = {}
var paths = "documents/settings/user".split('/')
paths.reduce(function(dir, path) {
return dir[path] = {}
}, dir)
console.log(dir)
Because the first parameter is always the last value returned (or the first value provided), all we need to do is return the object being assigned to the current path. And because an assignment results in the value being assigned, we can use that as the expression of the return statement itself.
If needed, you can guard against empty path names due to adjacent separators.
var dir = {}
var paths = "documents///settings/user".split('/')
paths.reduce(function(dir, path) {
return path ? (dir[path] = {}) : dir
}, dir)
console.log(dir)
Yet another elegant solution to build an object with value:
const buildObjWithValue = (path, value = '') => {
const paths = path.split('.');
return paths.reduceRight((acc, item, index) => ({
[item]: index === paths.length - 1
? value
: acc
}), {});
}
For example buildObjWithValue('very.deep.lake', 'Baikal') gives us
{
very: {
deep: {
lake: 'Bailkal'
}
}
}
Objects are passed by reference. You can use this feature and do something like this.
Array.forEach
var paths = "documents/settings/user".split('/')
var r = {};
var _tmp = r;
paths.forEach(function(el){
_tmp[el] = {};
_tmp = _tmp[el];
});
console.log(r)
For
var paths = "documents/settings/user".split('/')
var r = {};
var _tmp = r;
for(var i=0; i<paths.length; i++){
_tmp = (_tmp[paths[i]] = {});
};
console.log(r)

convert array to object javascript

I have the following array:
["recordList", "userList", "lastChanged"]
And I want something like this:
lastChangedValue = "231231443234";
var object = {};
object = {
recordList: {
userList: {
lastChanged: lastChangedValue
}
}
}
How I can do this?
Thanks in advance.
Try this:
var array = ["recordList", "userList", "lastChanged"];
var value = "231231443234";
function arrayToObject(array, object, value) {
var ref = object;
for (var i=0; i<array.length-1; ++i) {
if (!ref[array[i]]) {
ref[array[i]] = {};
}
ref = ref[array[i]]
}
ref[array[array.length-1]] = value;
return object;
}
alert(JSON.stringify(arrayToObject(array, {}, value)));
You can iterate through property names and create one nested level of new object in each iteration:
var props = ["recordList", "userList", "lastChanged"];
var lastChangedValue = "231231443234";
var obj = {}
var nested = obj;
props.forEach(function(o, i) {
nested[o] = i === props.length - 1 ? lastChangedValue : {};
nested = nested[o];
});
console.log(obj);
There are probably a bunch of ways to do it, one way is with reduce
var keys = ["recordList", "userList", "lastChanged"];
var temp = keys.slice().reverse(),
lastChangedValue = "231231443234";
var result = temp.reduce( function (obj, val, ind, arr) {
if (ind===0) {
obj[val] = lastChangedValue;
return obj;
} else {
var x = {};
x[val] = obj;
return x;
}
}, {});
console.log(result);
Solving with recursion
var fields = ["recordList", "userList", "lastChanged"];
lastChangedValue = "231231443234";
var object = {};
(function addFields(o, i, v) {
if (i == fields.length - 1) {
o[fields[i]] = v;
return;
}
o[fields[i]] = {};
addFields(o[fields[i]], ++i, v)
})(object, 0, lastChangedValue);
alert(JSON.stringify(object));

How to build nested properties from key strings

var keys1 = ["foo", "moreFoo"],
value1 = "bar",
keys2 = ["foo", "ultraFoo"],
value2 = "bigBar";
I'd like to make a function which would build me an object :
object {
foo : {moreFoo: "bar", ultraFoo: "bigBar"}
}
I thought of taking each one of my arrays and doing the following :
function recursiveObjectBuild(object, keys, value) {
var index = 0;
function loop(object, index) {
var key = keys[index];
//Property exists, go into it
if (key in object) {
loop(object[key], ++index);
//Property doesn't exist, create it and go into it
} else if (index < keys.length-1) {
object[key] = {};
loop(object[key], ++index);
//At last key, set value
} else {
object[key] = value;
return object;
}
}
return loop(object, 0);
}
Which should work IMO but doesn't (infinite loop, must be a stupid mistake but can't see it).
And I'm sure there must be a much simpler way
Try the following:
function objectBuild(object, keys, value) {
for (var i = 0; i < keys.length-1; i++) {
if (!object.hasOwnProperty(keys[i]))
object[keys[i]] = {};
object = object[keys[i]];
}
object[keys[keys.length-1]] = value;
}
Example usage (see it in action):
var object = {};
objectBuild(object, ["foo", "moreFoo"], "bar");
objectBuild(object, ["foo", "ultraFoo"], "bigBar");
// object --> {foo: {moreFoo: "bar", ultraFoo: "bigBar}}

Categories

Resources