I am trying to dynamically create an n dim object finalObj looking like this for n=3
children = { 'value1' : 'some1' , 'value2' : 'some2' , 'value3' :'some3' }
item = { 'key1' : 'value1' , 'key2':'value2' , 'key3':'value3' }
basically, the resulting object would look like this.
finalObj = { parent : { 'some1' : { 'some2' : { 'some3':{} } } } }
I am creating an n-depth Object below here.
var parent ={}
var finalObj
function makechildren( children, depth ){
if (depth>0){
makechildren({children}, depth-1);
}
else
{ finalObj=children
console.log('finalObj',finalObj)
}
return finalObj
}
Promise.resolve(makechildren(parent,4))
.then(function(resp){
console.log("resp is",resp);
})
This prints:
{ "children": { "children": { "children": { "children": {} } } } }
Now, how to turn
parent.children.children.children
with
item ={'key1':'value1','key2':'value2','key3':'value3'}
into
parent.children[ item['key1']].children[ item['key2']].children[ item['key3']]
which is essentially
parent.children['value1'].children['value2'].children['value3']....
I have tried making a copy of the original dictionary and altering the keys with a loop and assigning each parent.children[ item['key1']] to the rest of the multidimensional dictionary but didnt go really far.
parent1 = JSON.parse(JSON.stringify(parent))
for (i in Object.keys(parent))
{
parent1[ item['key'+i] ] = parent.children
}
However, iam stuck here on how to complete it this way. Any idea?
Loop through the values in item, using each one to get the corresponding value from children, and use this as the property for a new object. To make the nested object, use a variable to hold the object at the current depth, which you update each time through the loop.
children = { 'value1' : 'some1' , 'value2' : 'some2' , 'value3' :'some3' };
item = { 'key1' : 'value1' , 'key2':'value2' , 'key3':'value3' };
finalObj = { parent: {} };
var cur = finalObj.parent;
Object.values(item).forEach(val => {
cur[children[val]] = {};
cur = cur[children[val]];
});
console.log(JSON.stringify(finalObj));
Note that the order of items read from an object is not guaranteed, so there's no assurance that this will nest things in the desired order. You should use an array if you want order to be maintained.
Related
I have an object like this, that needs to be sent to an API -
var data = {
field : "category"
value : "order"
}
Now, this API also needs some conditions needed to be sent as nested objects. Something like this -
var data ={
field : "category"
value : "order"
AND : {
field : "circuit"
value : "ninth"
OR : {
field : "second"
value : "abc",
//more conditions here possible //
}
}
So, basically, a condition is nested inside a condition.
EDIT:: Note - Each condition added into the conditions array has to be nested into the previous condition
Now, I have an array of conditions -
conditionsArray = [
{filter: "AND", field: "circuit", value: "ninth"},
{filter: "OR", field: "second", value: "abc"}
]
How do I add conditions to data object from this conditionsArray in the most optimal way?
var data = {
field : "category"
value : "order"
}
Thank you for your time.
EDIT: sorry, I forgot to add what I have tried so far -
I have been trying to just form an object but this is by no means a good solution.
const check = () => {
console.log(conditionsArray);
const data: any = { ...fieldValue };
conditionsArray.forEach((condition: any) => {
const { filter, name, value } = condition;
const { AND, OR, NOT } = data;
if (AND || OR || NOT) {
if (AND) {
data["AND"][filter] = { name, value };
}
if (OR) {
data["OR"][filter] = { name, value };
}
if (NOT) {
data["NOT"][filter] = { name, value };
}
} else {
data[filter] = { name, value };
}
});
console.log(data,"log data");
};
You could reduce the array and return the nested object for the next iteration.
const
data = { field: "category", value: "order" },
conditionsArray = [{ filter: "AND", field: "circuit", value: "ninth" }, { filter: "OR", field: "second", value: "abc" }];
conditionsArray.reduce((o, { filter, ...rest }) => o[filter] = rest, data);
console.log(data);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Using recursion :
function addConditions(data, conditions) {
if (conditions.length == 0) { return data; }
var topMostCondition = conditions[0];
var objectToAdd = { field : topMostCondition.field, value : topMostCondition.value };
data[topMostCondition.filter] = addConditions(objectToAdd, conditions.splice(1));
return data;
}
If your conditionsArray items should be added in the order of appearance to data, you may go recursive way like that:
const conditionsArray=[{filter:"AND",field:"circuit",value:"ninth"},{filter:"OR",field:"second",value:"abc"}],
data={field:"category",value:"order"},
makeATree = (o, list, branch) => {
if(!list.length) return o
const [condition, ...restOfConditions] = list,
{filter, ...rest} = condition
return makeATree(
{
...o,
...(
!branch ?
{[filter]: rest} :
{[branch]: {...o[branch], [filter]: rest}}
)
},
restOfConditions,
filter
)
}
console.log(makeATree(data, conditionsArray))
.as-console-wrapper{min-height:100%;}
I have an array imported via AJAX.
I want to create a new array based on the original one and scan through the whole new array in order to clean the value WHATEVER the key associated to it.
The imported dataset looks like this:
[
{id:"1", color:"red_blue", height:"100_200" },
{id:"2", color:"green", height:"100_20" },
{id:"3", color:"orange_yellow", height:"50" }
]
And the jQuery process looks like this
dataSet = JSON.parse(response);
// create a new array based on the imported array
var row = 0;
$.each(dataSet, function(key, value) {
cleanDataSet.push(dataSet[row]);
row++;
});
// clean the new array
var row = 0;
// Go through each row of the array
$.each(cleanDataSet, function(key, value) {
// Go through each key and value of this array
$.each(cleanDataSet[row], function(key, value) {
var myVariable = thisValueWhateverTheKey.split('_');
// if a split is detected in the value
if (myVariable[1]) {
// Update the value
thisValueWhateverTheKey = myVariable[0];
}
row++;
});
});
console.log(cleanDataSet)
The "thisValueWhateverTheKey" part is obviously the one I can't figure out.
It's easy when I target the values of a specific key (I would use "value.nameofmykey" but not that much when I target any value of any key. "value" alone won't work.
You can use value directly, most probably you're geting confused by using key, value in both loops. Also note that you're splitting on double underscore __ which needs to be a single one _ as per your data.
Here's how you can simplify:
$.each(cleanDataSet, function(index, cleanDataSetRow){
// Go through each key and value of this array
$.each(cleanDataSetRow, function(key, value){
var myVariable = value.split('_');
// if a split is detected in the value
if(myVariable[1]){
// Update the value
cleanDataSetRow[key] = myVariable[0];
}
});
});
I think your code/question is a little confusing - if I understand it properly you are wanting something like this. Note the map function creates a new array populated with the results of calling a provided function on every element in the calling array. e.g.
const data = [{
id: "1",
color: "red_blue",
height: "100_200"
},
{
id: "2",
color: "green",
height: "100_20"
},
{
id: "3",
color: "orange_yellow",
height: "50"
}
]
const clean = data.map(x => {
// x is each object in the original array
// i.e. data[0], data[1], etc
for (y in x) {
// y is each property in the object
// e.g. data[0]["id"], data[0]["color"], etc
// so here we are setting the value of each property of each object
x[y] = x[y].split('_')[0]
}
// finally return each modified object
return x;
})
// so clean is a new array based on data
// where each property has been set to the correct value
console.log(clean)
If this isn't correct could you possibly edit your question to included and example of how you want the data to look - i.e. before/after.
const data = [
{
id: "1",
color: "red_blue",
height: "100_200"
},
{
id: "2",
color: "green",
height: "100_20"
},
{
id: "3",
color: "orange_yellow",
height: "50"
}
];
var clean = data.map(item => Object.fromEntries(
Object.keys(item).map(key => [key, item[key].split('_')[0]])
));
console.log(clean);
When you iterate through each object use Object.entries() and destruct each entry (ex. [key, value]):
...
Object.entries(obj).forEach(([key, val]) => {
if (val === value) {
obj[key] = ''
}
...
let data = [
{id:"1", color:"red_blue", height:"100_200" },
{id:"2", color:"green", height:"100_20" },
{id:"3", color:"orange_yellow", height:"50" }
];
function removeValue(objectArray, value) {
objectArray.forEach(obj => {
Object.entries(obj).forEach(([key, val]) => {
if (val === value) {
obj[key] = '';
}
});
});
return objectArray;
}
console.log(removeValue(data, "100_20"));
console.log(removeValue(data, "orange_yellow"));
let's say I have a nested object like this:
let object = {
another : {
yet_another : {
last_one : {
some_property : [1,2,3]
}
}
}
}
I can access some_property like this:
object.another.yet_another.last_one.some_property;
And let's say I'm referring to this object in a variable:
var x = object.another.yet_another.last_one.some_property;
How can I tell what's the parent object of some_property if I only have access the x variable? is it even possible in JavaScript?
No, it's not possible. An object doesn't have a "parent" per se. Observe:
let object = {
another : {
yet_another : {
last_one : {
some_property : [1,2,3]
}
}
}
};
let another_object = {
foo: object.another.yet_another.last_one.some_property
};
Now what? The array is now equally a member of both objects.
No, because when doing the following line;
var x = object.another.yet_another.last_one.some_property;
then you assign x to the value of some_property, nothing more.
Based on your comment to an answer, the solution to your (actual) problem should be don't move objects around. Mutability can be very very expensive (eventually prohibitively) when it comes to maintaining an application.
Just create new objects:
const firstObject = {
prop1: 'some value',
prop2: {
prop3: 'some value',
prop4: [1,2,3,4]
}
}
// don't do
const secondObject = { }
secondObject.prop2.prop4 = firstObject.prop2.prop4
// instead do
const secondObject = { ... }
const newObject = {
...secondObject,
prop2: {
...secondObject.prop2,
prop4: firstObject.prop2.prop4
}
}
You may want to look into immutablejs.
How to add attribute to the root of JSON object consists of array of objects?
If my JSON object something like that:
[
{
"Id":"f2ac41c5-b214-48f6-ad40-9fc35c1aaad9",
"Name":"W",
"NumberOfWorkHours":8,
"NumberOfShortDays":1,
"WorkTimeRegulationId":"f5833075-2847-4cc3-834d-6138dd0dcd99"
},
{
"Id":"5c267601-fcf2-4735-9e49-b4def3981648",
"Name":"S",
"NumberOfWorkHours":6,
"NumberOfShortDays":0,
"WorkTimeRegulationId":"8d14580e-278f-41d1-9239-8874be792580"
}
]
I do the following:
worktimeJSON.Id = $('.Js-WorkTime-id').val();
worktimeJSON.Name = $('.Js-WorkTime-name').val();
worktimeJSON.NumberOfAvailableRotations = $('.Js-WorkTime-rotations').val();
And make sure that the jQuery fetching data from the inputs but this doesn't work.
This will change property of all object in array if you want to change in particular then use index for this for exp->
worktimeJSON[0].Id = $('.Js-WorkTime-id').val();
worktimeJSON[0].Name = $('.Js-WorkTime-name').val();
worktimeJSON[0].NumberOfAvailableRotations = $('.Js-WorkTime-rotations').val();
var worktimeJSON = [
{
"Id":"f2ac41c5-b214-48f6-ad40-9fc35c1aaad9",
"Name":"W",
"NumberOfWorkHours":8,
"NumberOfShortDays":1,
"WorkTimeRegulationId":"f5833075-2847-4cc3-834d-6138dd0dcd99"
},
{
"Id":"5c267601-fcf2-4735-9e49-b4def3981648",
"Name":"S",
"NumberOfWorkHours":6,
"NumberOfShortDays":0,
"WorkTimeRegulationId":"8d14580e-278f-41d1-9239-8874be792580"
}
];
worktimeJSON = worktimeJSON.map(function(val){
val.Id = $('.Js-WorkTime-id').val();
val.Name = $('.Js-WorkTime-name').val();
val.NumberOfAvailableRotations = $('.Js-WorkTime-rotations').val();
return val;
});
Push can do the job.
let worktimeJSON = [
{
"Id":"f2ac41c5-b214-48f6-ad40-9fc35c1aaad9",
"Name":"W",
"NumberOfWorkHours":8,
"NumberOfShortDays":1,
"WorkTimeRegulationId":"f5833075-2847-4cc3-834d-6138dd0dcd99"
},
{
"Id":"5c267601-fcf2-4735-9e49-b4def3981648",
"Name":"S",
"NumberOfWorkHours":6,
"NumberOfShortDays":0,
"WorkTimeRegulationId":"8d14580e-278f-41d1-9239-8874be792580"
}
];
worktimeJSON.push
({
id: "someID",
name: "toto",
WorkTimeRegulationId: 42
});
console.log(worktimeJSON);
I structure my object like this:
let WorkTimeRegulationViewModelJSON = {
Id: $('.Js-WorkTimeRegulation-id').val(),
Name: $('.Js-WorkTimeRegulation-name').val(),
NumberOfAvailableRotations: $('.Js-WorkTimeRegulation-rotations').val(),
AssignedWorkTimes: JSON.parse(worktimeJSON)
};
I'm just wondering if it's possible to refer to self (object) value inside the object sibling like below?
[
{
"name": "Zulh",
"name_uppercase": uppercase(self.name) // expects ZULH
},
{
"name": "John",
"name_uppercase": uppercase(self.name) // expects JOHN
}
]
Note:
Code for uppercase is omitted for brevity. In my real code, it's doing synchronous complex stuff and is not actually simple string case manipulation like that.
Using a GETTER
If you want to keep it dynamic and make it work even if you change the name property, you can use a GETTER to do this kind of thing:
const names = [
{
"name": "John",
get name_uppercase() {
return this.name.toUpperCase();
}
}
]
console.log(names[0].name_uppercase)
GETTER for multiple objects
You don't have to write this for every property manually! Use .forEach:
const names = [
{
"name": "John"
},
{
"name": "Mike"
}
]
names.forEach(object => {
Object.defineProperty(object, 'nameUppercase', {
get: function() { return this.name.toUpperCase() }
});
});
console.log(names[0].nameUppercase)
console.log(names[1].nameUppercase)
Using a class and a GETTER
Or as #Rajesh pointed out you can use a class instead:
class Person {
constructor(name) {
this.name = name;
}
get nameUpperCase() {
return this.name.toUpperCase();
}
}
const names = [ new Person("John"), new Person("Mike")];
console.log(names[0].nameUpperCase);
console.log(names[1].nameUpperCase);
You can't reference an object during initialization when using object literal syntax.. Inshort, that's not possible what you expect above
Well, you can use map and add additional/modified properties to you object like
data.map(o=> ({name: o.name, upper_case : o.name.toUpperCase()}))
var data = [
{
"name": "Zulh"
},
{
"name": "John"
}
];
var x = data.map(o=> ({name: o.name, upper_case : o.name.toUpperCase()}))
console.log(x)
You can use Array.forEach and update the objects in Array
var data = [{"name": "Zulh"},{"name": "John"}];
data.forEach(o=> o.upper_case = o.name.toUpperCase());
console.log(data);
Why not create a function that transforms your incoming array? A way to do it could be like this:
const value = [
{
"name": "Zulh"
},
{
"name": "John"
}
];
const transform = ( array, propertyToUpdate, propertyToCreate, transformation ) => {
return array.map( item => ({ ...item, [propertyToCreate]: transformation( item[propertyToUpdate] ) }) );
};
console.log( transform( value, 'name', 'name_uppercase', ( item ) => item.toUpperCase() ) );
You can't do this with the object literal syntax, since it's 'this' property will not be set at that time. For example, if you'd run your code in the browser, 'this' would refer to the window object.
So you'll either have to use one of the other answers or go for a 'class':
var uppercase = function( str ) {
return str.toUpperCase();
};
var Person = function( name ) {
this.name = name;
this.name_uppercase = uppercase( this.name );
};
var persons = [
new Person( 'zuhi' ),
new Person( 'john' )
];
console.log( persons );
Same can be written in ES6 class syntax.
I would suggest 2 approaches:
If you DO NOT want to change your initial array ( which is recommended ), use map which returns a new array with changed values ( calls a function for every array item ) .
See below
let arr = [
{
"name": "Zulh",
},
{
"name": "John",
}
];
const newArr = arr.map((x)=>{
x.name_uppercase = (x.name).toUpperCase()
return x
})
console.log(newArr)
If you don't mind changing your initial array, you can use forEach. Keep in mind that unlike map, forEach changes your array and so it doesn't return anything.
let arr = [
{
"name": "Zulh",
},
{
"name": "John",
}
];
arr.forEach((x)=>{
x.name_uppercase = (x.name).toUpperCase()
})
console.log(arr)
So it all depends if you want to change your current array or not
How about using a getter method?
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/get
The get syntax binds an object property to a function that will be
called when that property is looked up.
foo = [
{
"name": "Zulh",
get name_uppercase () {
return (this.name).toUpperCase();
}
},
{
"name": "John",
get name_uppercase () {
return (this.name).toUpperCase();
}
}
]
console.log(foo[1].name_uppercase); //returns JOHN
Hope it helps :)