I need to access into myObject using a generic function.
Data:
myObject = {
"name": "Caroline",
"number": 32,
"country": {
"province": {
"city": {
"NY": 67989876,
"Boston": 454346,
}
}
}
}
myArray = ["country", "province", "city"]
The solution would be:
myObject["country"]["province"]["city"]
I want rewrite after myObject, then the solution can not be a copy
myObject["country"]["province"]["city"] = "New datas"
var data = myObject;
for (var i in myArray) {
data = data[myArray[i]];
}
alert(data);
Fiddle https://jsfiddle.net/g2uyb8rn/
Shorter version by #JeremyThille is:
var data = myObject;
for (let i of myArray) data = data[i];
alert(data);
Related
What I would like to do is to process JSON data and store each object after getting out of the for loop. However, the obj gets updated every iteration, so the objectArray holds only David's information in each element in it. I would like the objArray to hold each of the processed JSON objects (screenshot below). The JSON process is to store search a userId and name and store them in the objectArray. Could someone help me figure out how I could store each object in the objectArray? Thank you in advance.
const obj = {};
var objectArray = [];
var data = [
{
"userId": "123",
"name": "John",
"phoneNumber": "123-456-6789"
},
{
"userId": "345",
"name": "Summer",
"phoneNumber": "535-631-9742"
},
{
"userId" : "789",
"name": "David",
"phoneNumber": "633-753-1352"
}
]
var dataLen = data.length;
var people = data;
createKeyValue = ((key, value) => {
var temp = {};
temp["value"] = value;
obj[key] = temp;
});
while (dataLen > 0) {
for (let [key, value] of Object.entries(data[0])) {
switch(key) {
case 'userId':
createKeyValue(key, value);
break;
case 'name':
createKeyValue(key, value);
break;
default:
}
}
objectArray.push(obj);
data.shift();
dataLen -= 1;
}
You can do this using a simple forEach() loop to create and push new objects to the objArray array.
const data = [
{
"userId": "123",
"name": "John",
"phoneNumber": "123-456-6789"
},
{
"userId": "345",
"name": "Summer",
"phoneNumber": "535-631-9742"
},
{
"userId": "789",
"name": "David",
"phoneNumber": "633-753-1352"
}
];
let objArray = [];
data.forEach(person => {
objArray.push({
userId: { value: person.userId },
name: { value: person.name }
});
});
console.log(objArray);
The error you're seeing is because of a concept in JavaScript (and programming in general) known as "passing by reference."
Objects in JS, instead of being passed as whole groups of data, are passed around as addresses to where that data is stored. This saves a lot of overhead, since objects can become quite large.
In your case however, you're running into one of the ways it can trip you up. Since obj is really getting passed by reference instead of value, you're really .pushing 3 copies of the same address (of obj) onto objectArray rather than 3 distinct sets of data.
A better approach to this problem would be using a JS Array function called map(). This function is probably best explained by MDN:
The map() method creates a new array populated with the results of calling a provided function on every element in the calling array.
You can use it on your data array like this:
var objectArray = [];
var data = [{
"userId": "123",
"name": "John",
"phoneNumber": "123-456-6789"
},
{
"userId": "345",
"name": "Summer",
"phoneNumber": "535-631-9742"
},
{
"userId": "789",
"name": "David",
"phoneNumber": "633-753-1352"
}
]
objectArray = data.map(dataEl => ({
userId: {
value: dataEl.userId,
},
name: {
value: dataEl.name,
},
}));
console.log(objectArray);
.as-console-wrapper {
max-height: 100% !important;
}
As said by our friends Kevin B and Zcoop98, its more appropriate to use forEach function, not map function:
data.forEach(elem => {
objectArray.push({
userId: { value: elem.userId },
name: { value: elem.name }
});
})
I have a CSV file which needs to be converted into a Javascript object / JSON file. Doesn't really matter which since I'll be be handling the data in JS anyway and either is fine.
So for instance this:
name,birthday/day,birthday/month,birthday/year,house/type,house/address/street,house/address/city,house/address/state,house/occupants
Lily Haywood,27,3,1995,Igloo,768 Pocket Walk,Honolulu,HI,7
Stan Marsh,19,10,1987,Treehouse,2001 Bonanza Street,South Park,CO,2
should become this:
[
{
"name": "Lily Haywood",
"birthday": {
"day": 27,
"month": 3,
"year": 1995
},
"house": {
"type": "Igloo",
"address": {
"street": "768 Pocket Walk",
"city": "Honolulu",
"state": "HI"
},
"occupants": 7
}
},
{
"name": "Stan Marsh",
"birthday": {
"day": 19,
"month": 10,
"year": 1987
},
"house": {
"type": "Treehouse",
"address": {
"street": "2001 Bonanza Street",
"city": "South Park",
"state": "CO"
},
"occupants": 2
}
}
]
This is what I have came up with:
function parse(csv){
function createEntry(header){
return function (record){
let keys = header.split(",");
let values = record.split(",");
if (values.length !== keys.length){
console.error("Invalid CSV file");
return;
}
for (let i=0; i<keys.length; i++){
let key = keys[i].split("/");
let value = values[i] || null;
/////
if (key.length === 1){
this[key] = value;
}
else {
let newKey = key.shift();
this[newKey] = this[newKey] || {};
//this[newKey][key[0]] = value;
if (key.length === 1){
this[newKey][key[0]] = value;
}
else {
let newKey2 = key.shift();
this[newKey][newKey2] = this[newKey][newKey2] || {};
this[newKey][newKey2][key[0]] = value;
//if (key.length === 1){}
//...
}
}
/////
}
};
}
let lines = csv.split("\n");
let Entry = createEntry(lines.shift());
let output = [];
for (let line of lines){
entry = new Entry(line);
output.push(entry);
}
return output;
}
My code works, however there is an obvious flaw to it: for each layer it goes down into (e.g. house/address/street), I have to manually write repeated if / else statements.
Is there a better way to write it? I know this involves recursion or iteration of some kind but I just can't seem to figure out how.
I've searched around SO but most questions seem to be on doing it in Python instead of JS.
As far as possible I wish to have this done in vanilla JS without any other libraries.
You can achieve the intended results by creating the Object recursively.
Look at the code below:
var csv = [
"name,birthday/day,birthday/month,birthday/year,house/type,house/address/street,house/address/city,house/address/state,house/occupants",
"Lily Haywood,27,3,1995,Igloo,768 Pocket Walk,Honolulu,HI,7",
"Stan Marsh,19,10,1987,Treehouse,2001 Bonanza Street,South Park,CO,2"
];
var attrs = csv.splice(0,1);
var result = csv.map(function(row) {
var obj = {};
var rowData = row.split(',');
attrs[0].split(',').forEach(function(val, idx) {
obj = constructObj(val, obj, rowData[idx]);
});
return obj;
})
function constructObj(str, parentObj, data) {
if(str.split('/').length === 1) {
parentObj[str] = data;
return parentObj;
}
var curKey = str.split('/')[0];
if(!parentObj[curKey])
parentObj[curKey] = {};
parentObj[curKey] = constructObj(str.split('/').slice(1).join('/'), parentObj[curKey], data);
return parentObj;
}
console.log(result);
.as-console-wrapper{max-height: 100% !important; top:0}
constructObj() function basically constructs the resultant object recursively by looking at the column name, so if the column name contains the / like in house/address/street it will create a key in the object by the name house and then recursively calls itself for the rest of the remaining keys in string i.e. address/street/. The recursion ends when no more / are left in the string and then it simply assigns the value in that key and returns the result object.
You can map over your records and create the objects on the fly :
let records = ['Lily Haywood,27,3,1995,Igloo,768 Pocket Walk,Honolulu,HI,7',
'Stan Marsh,19,10,1987,Treehouse,2001 Bonanza Street,South Park,CO,2']
let output = records.map( record => {
let arr = record.split(',')
return {
"name": arr[0],
"birthday": {
"day": parseInt(arr[1]),
"month": parseInt(arr[2]),
"year": parseInt(arr[3])
},
"house": {
"type": arr[4],
"address": {
"street": arr[5],
"city": arr[6],
"state": arr[7]
},
"occupants": parseInt(arr[8])
}
}
})
console.log(output)
Hi I am trying push a javascript object inside an array in javascript using a for loop to iterate through the data. Here is how my code looks like.
var data = {"up": [{
"name": "jack",
"age" : 10
},
{
"name" : "jhon",
"age" : 12
}]};
var output = {};
var output_data = {
element: []
};
for (var key in data.up) {
output.user_name = data.up[key].name;
output_data.element.push(output);
}
console.log(output_data.element);
However as you can see in the example http://jsbin.com/fanazaxoda/edit?html,js,console only the second element is name 'jhon' is inserted in both occations. What am I doing wrong here? Please explain.
Move the output initialization inside for loop otherwise it push reference of object each time. Updating it's property may reflect in all array elements since all elements are referring the same object.
var output_data = {
element: []
};
for (var key in data.up) {
var output = {}; // create new empty object on each iteration
output.user_name = data.up[key].name;
output_data.element.push(output);
}
var data = {
"up": [{
"name": "jack",
"age": 10
}, {
"name": "jhon",
"age": 12
}]
};
var output_data = {
element: []
};
for (var key in data.up) {
var output = {};
output.user_name = data.up[key].name;
output_data.element.push(output);
}
console.log(output_data.element);
I have a set of JSON object in a text file called text.json which looks like the following:
{
"school": [
{
"student": {
"name": "John",
"lastname": "Ghram",
"studentId": "000111"
}
},
{
"student": {
"name": "Harry",
"lastname": "Smith",
"studentId": "000112"
}
},
{
"teacher": {
"name": "Teacher One",
"teacherId": 1001
}
}
]
}
The following code is use to read from file
var obj = (function () {
var json = null;
$.ajax({
'async': false,
'global': true,
'url': "text.json",
'dataType': "json",
'Content-type': 'application/json',
'success': function (data) {
obj = data;
}
});
return obj;
})();
When the obj is returned to get the name of student name I am using
obj.school[0].student['name'].
is there a way to store all student information as one JSON object called students and the teacher to other called teachers, so I can access the info without using the index number. For Eg: student.name.
No, this is exactly what arrays are for. You cannot store multiple instances of the name property on one object, that makes no sense. How would student.name possibly resolve to a single name, if student represented multiple students?
I've formatted your json and then applied a for loop to find object keys that match 'student' and then augmented the students object with the name.
If two names are the same, they'll be overwritten, so this isn't the best approach:
var obj = {
"school": [
{"student": { "name":"John", "lastname": "Ghram", "studentId": 000111 }},
{"student": { "name": "Harry","lastname": "Smith", "studentId": 000112 }},
{"teacher": { "name": "Teacher One", "teacherId": 1001 }}
]
};
var i, arr = obj.school, len = arr.length;
var students = Object.create(null);
for(i=0; i<len; i++) {
if(Object.keys(arr[i])[0] === 'student') students[arr[i].student.name] = arr[i];
}
Can now use square-bracket notation:
students['John'], students['Harry'], etc
You just need to new an array to store them, you can write a function like this
function getStudents(obj)
{
var res = new Array() ;
var school = obj['school'] ;
for(item in school)
{
for(q in school[item])
{
if(q=="student")//you can change it to "teacher"
{
res.push(school[item]) ;
}
}
}
console.log(res) ;
return res ;//return an array(object) of students;
}
getStudents(obj) ;
(context)I have information from a bunch of elements that I'm collecting into a JSON object that then gets passed down to an MVC3 controller where it gets deserialized into an object.
There are 'items' and 'item settings'. Currently, I have have both items and item settings all in flat JSON object. Ideally I would like to have the item settings nested under each item. My code currently looks like this:
var editeditems=[];
...
$("#SaveChanges").click(function() {
//this works and retrieves all of the item IDs
$(".portlet").each(function() {
var itemname = $(this).data("itemname");
editeditems.push(
{
"itemname": itemname
});
itemname = $(this).data("itemname");
$(".settingInput").each(function() {
editeditems.push(
{
"settingkey":$(this).attr("name"),
"settingvalue":$(this).attr("value")
});
});
});
Under the $(".settingInput").each function is where the settings get added. I've tried syntax like 'editedItems.settings.push..' but it returns with a syntax error.
Any help would greatly be appreciated!
var editeditems = [];
...
$('#SaveChanges').click(function() {
$('.portlet').each(function() {
var settings = [];
$('.settingInput').each(function() {
settings.push({
settingkey: $(this).attr('name'),
settingvalue: $(this).attr('value')
});
});
editeditems.push({
itemname: $(this).data('itemname'),
settings: settings
});
});
...
});
will generate sample output:
var editeditems =
[
{
"itemname": "item1",
"settings": [
{
"settingkey": "key1",
"settingvalue": "value1"
},
{
"settingkey": "key2",
"settingvalue": "value2"
}
]
},
{
"itemname": "item2",
"settings": [
{
"settingkey": "key1",
"settingvalue": "value3"
},
{
"settingkey": "key2",
"settingvalue": "value4"
}
]
}
];
var ei = {'settings': [3]};
ei.settings.push(4);
console.log(ei);
// This will output an object with property settings and value an array with values (3 and 4)
You need to create flat data array json as:
[{"itemname": "item1","settingkey": "key1","settingvalue": "value1"},
{"itemname": "item2","settingkey": "key2","settingvalue": "value2"},];
Than process the above date like this
var keys = Object.keys(dataMap);
var json = [];
for (var key in keys) {
var innerJson = {};
innerJson["name"] = keys[key];
var innerMap = dataMap[keys[key]];
if (innerMap instanceof Array) {
innerJson["size"] = innerMap[0];
} else if (innerMap instanceof Object) {
var child = processHirarchiachalData(innerMap);
innerJson["children"] = child;
}
json.push(innerJson);
}