Given an javascript object:
myList = {
"1": "Winter",
"2": "Spring",
"3": "Summer",
"4": "Fall"
}
and supposing that the variable season contains the first item, how do I access "1" and/or "Winter"?
Edit: myList['1'] is not the answer I am looking for because I want to access either "1" or "Winter" from the season variable. It is not a duplicate of the marked question.
Instead, I want to do something like:
for(var season in myList) {
foo( season.key ); // should be "1" on the first pass
bar( sesson.val ); // should be "Winter" on the first pass
}
I've seen somewhere that you can do an inner loop to get the key and value. Is there some other way aside from doing that?
Libraries like lodash and underscore were made to help with these kinds of problems. You can use the lodash#forEach function to iterate over the values (and keys if applicable) in a collection (array or object).
Check out: https://lodash.com/docs#forEach
So with your example you could do something like:
_.forEach(myList, function(value, key) {
foo(key); // 1
bar(value); // "Winter"
});
You can simply get the value of the key by:
myList['1']
To get the key from the value there is no standard method available in javascript. You would have to write your own method for this.
Related
I had the following object:
var dataset = [
[
{"value":"PRE","formattedValue":"PRE"},
{"value":"2017-06-15 00:00:00","formattedValue":"15/06/2017 0:00:00"},
{"value":"COSTA RICA","formattedValue":"COSTA RICA"},
{"value":"6.15","formattedValue":"6,150"}
],
[
{"value":"PRE","formattedValue":"PRE"},
{"value":"2017-06-15 00:00:00","formattedValue":"15/06/2017 0:00:00"},
{"value":"EL SALVADOR","formattedValue":"EL SALVADOR"}
]
]
Its too complex and has data I don't actually need, so I tried to turn it into this:
[
{
"estado": "PRE",
"fecha": "2017-06-15 00:00:00",
"pais": "COSTA RICA",
"precio": "6.15",
}
]
I finally did it, but I'n unsure why my code works.
I done it with this code:
var datafinal = [];
function convertion(){
var dataobj = dataset.getData();
for(var x in dataobj){
datafinal[x] = { "estado": dataobj[x][0]["value"] };
datafinal[x]["fecha"] = dataobj[x][1]["value"];
datafinal[x]["pais"] = dataobj[x][2]["value"];
datafinal[x]["precio"] = dataobj[x][3]["value"];
}
}
If you pay attention, you'll see the first value i add to the new object is using a different format to get added than the rest.
I discovered that if i add every value with the second format it adds nothing.
But if i add everything in the first format, it only adds the last value;
So, i made the vale in the first format, and the rest in the second format, and it worked just fine.
...why though, can someone explain to me why is this happening?
This is because at first datafinal[x] does not yet exist, so you need to give it a value, i.e. assign it an object. That is what the first assignment does. The other assignments are mutating the existing value, since you don't want them to replace the value you assigned in the first line.
Notice the other assignments don't assign to datafinal[x] itself, but write to a property of it: so you extend the object that you assigned in the first assignment.
In fact, the first assignment could be broken into two parts:
datafinal[x] = {};
datafinal[x].estado = dataobj[x][0].value;
... and so now all property assignments could look the same (NB: you don't need the square bracket notation for these literal property names). The first assignment is now just initialising the value as an object (as opposed to a number, a string, a boolean...). Without such assignment, you don't have an object, and cannot assign properties to it.
You could maybe make it easier to understand if you would write it in one object literal assignment:
datafinal[x] = {
estado: dataobj[x][0].value,
fecha: dataobj[x][1].value,
pais: dataobj[x][2].value,
precio: dataobj[x][3].value
};
In the current form you are initialling telling it to create an object at that position and 'initialising' it with a value of { "estado": dataobj[x][0]["value"] };.
Subsequent attempts to access the object datafinal[x] then access a property of that object and as that property does not yet exist, creates it with your given value.
By simple repeating the line datafinal[x] = { "estado": dataobj[x][0]["value"] }; as you suggest with the different keys and values, you are merely overwriting
the value of datafinal[x] with a new object each time.
EDIT:
As for why only adding the values in your second format does not work, this is down to the fact that in doing so you are trying to access properties of an object datafinal[x] that does not yet exist. Whereas, by doing one call in your first format creates that object.
If you use your first format it will rewrite all your object everytime you call it
datafinal[x] = { "estado": dataobj[x][0]["value"] };
means that datafinal[x] is equal to that so if you do
datafinal[x] = { "fecha" = dataobj[x][1]["value"] };
it will erase what's in datafinal[x]
that is why your first format doesn't work
Here is my JSON file below. Each object in the array belongs to an Id. So the first object would be #one, second object would be for #two. and so on. I can not figure out how to write this in JavaScript. How can I target which array number[1] with object[1] appends to #two for example? Also I need to delete the first line of the object which is the count line? Thank you!
so to get more into details. I was given an assignment, where I have placed pictures in the html and underneath the pictures, each object in the json file(description for the pictures) is supposed to go underneath it. I am new wtih json and ajax :( so the ids #one, #two... were just examples. There would be 6 ids. one for each object.
[
[
{
"count": "80",
"countTxt":"Buyer logins",
"participantsTxt":"Total for all participating member companies:",
"participantCount":"523"
},
{
"count": "233",
"countTxt":"Searches",
"participantsTxt":"Total for all participating member companies:",
"participantCount":"628"
},
{
"count": "533",
"countTxt":"Views of our member pages",
"participantsTxt":"Total for all participating member companies:",
"participantCount":"2,365"
}
],
[
{
"count": "80",
"countTxt":"Total vists",
"participantsTxt":"Total for all participating member companies:",
"participantCount":"412"
},
{
"count": "53",
"countTxt":"Unique visitors",
"participantsTxt":"Total for all participating member companies:",
"participantCount":"731"
},
{
"count": "1:12 min",
"countTxt":"Total time spent on page",
"participantsTxt":"Total for all participating member companies:",
"participantCount":"784.2 mins"
}
]
]
You have an array containing arrays which contain objects. They don't appear to have those IDs in them anywhere, and with names like #one, #two, and such, it's awkward to assign those (you basically have to have a list of names waiting to be assigned).
The work itself is relatively simple once you have that list:
Parse the JSON into an object graph via JSON.parse.
var outerArray = JSON.parse(jsonText);
Create a blank object you can save the named objects to as properties, like a map:
var map = {};
Type in your list of IDs as an array:
// This assumes no more than 99 elements
var ids = [
"#one", "#two", "#three", /*...and so on...*/, "#ninety-nine"
];
Have an index variable that starts with 0.
Loop through the outermost array; you have lots and lots of options for how to do that, I'd probably use forEach:
outerArray.forEach(function(nestedArray) {
// ...more code here
});
Inside that loop, loop through the objects in the nested array:
outerArray.forEach(function(nestedArray) {
nestedArray.forEach(function(object) {
// ...more code here
});
});
Inside the inner loop, add the current object to your map using the next available ID via your index variable:
map[ids[index++]] = object;
If you really want to, remove the count property from the object:
delete object.count;
So putting it all together:
var index = 0;
var outerArray = JSON.parse(jsonText);
var map = {};
var ids = [ // This assumes no more than 99 elements
"#one", "#two", "#three", /*...and so on...*/, "#ninety-nine"
];
outerArray.forEach(function(nestedArray) {
nestedArray.forEach(function(object) {
map[ids[index++]] = object;
delete object.count; // Doesn't matter whether this is before or after the line above
});
});
Notes:
It's going to be really awkward to access those objects with IDs like #one and such, but I assume you have a reason for it. You do map["#one"] and such to get at the objects.
If you don't have to delete the count property, don't bother.
First, you might want to ask yourself if your current way of formatting the data is appropriate. Currently, your data is formatted like this:
var jsonObject =
[
[{},{},{}],
[{},{},{}]
];
Where you have an outermost array, that contains two arrays, and the json data/javascript objects are then stored inside of those arrays. There probably isn't a need for the outermost array, and it would simplify the way you access the data inside of your json object without it. So keep in mind that all the examples you get here on SO are going to refer to the JSON object as you presented it.
// List off all "countTxt" objects to demonstrate how to
// iterate over a json object that contains nested
// arrays containing data. In your example, you have two arrays
// that each contain json data.
for (var i in jsonObject) {
for (var j in jsonObject[i]){
console.log(jsonObject[i][j].countTxt);
}
}
The above loop will print out the following:
/*
Unique visitors
Total time spent on page
Buyer logins
Searches
Views of our member pages
Total vists
Unique visitors
Total time spent on page
*/
Warning: as T.J. Crowder pointed out, using for..in loops to access json data will come back to bite you, so using this type of for..in looping structure (above) isn't recommended in production code, but it serves as a simple demonstration how you use access notation [] to grab values from an array of data objects. To read up on some best practices, you can read T.J. Crowder's in-depth post on the subject here.
If you want to target a specific item in the jsonObject, you do so like this:
// Grab the second object in the data array:
var secondObjectInJsonData = jsonObject[1];
console.log(secondObjectInJsonData);
// secondObjectInJsonData -> [Object, Object, Object]
If you want to grab specific data inside the data array:
// Grab the second object, inside the first array of json data
var countTxtOfSecondObject = jsonObject[0][2].countTxt;
console.log(countTxtOfSecondObject);
// countTxtOfSecondObject --> "Views of our member pages"
To Delete an object, you can use the delete command
var someObject = jsonObject[1][2];
delete someObject.count;
console.log("someObject after 'count' has been deleted: ", someObject);
Here is a JSFiddle to see all this code in action. Just open up the console in Chrome Developer Tools (in the Chrome browser) to see the output of all the console.log() statements.
First of all, You should reformat your data, Try using JSON Editor Online, this shows a tree view of your data. Chrome Extension is available for this, Please check the Chrome web store. It's a really good practice.
I've reformatted your data and made it into something which is more readable. Take a look;
[
{
"count": "80",
"countTxt":"Buyer logins",
"participantsTxt":"Total for all participating member companies:",
"participantCount":"523"
},
{
"count": "233",
"countTxt":"Searches",
"participantsTxt":"Total for all participating member companies:",
"participantCount":"628"
},
{
"count": "533",
"countTxt":"Views of our member pages",
"participantsTxt":"Total for all participating member companies:",
"participantCount":"2,365"
},
{
"count": "80",
"countTxt":"Total vists",
"participantsTxt":"Total for all participating member companies:",
"participantCount":"412"
},
{
"count": "53",
"countTxt":"Unique visitors",
"participantsTxt":"Total for all participating member companies:",
"participantCount":"731"
},
{
"count": "1:12 min",
"countTxt":"Total time spent on page",
"participantsTxt":"Total for all participating member companies:",
"participantCount":"784.2 mins"
}
]
You can access the JSON data using jQuery.getJSON() method and use jQuery.each method to loop through the object. Try this out;
$.getJSON('data.json', function(data) {
$.each(data, function(k) {
console.log(data[k]);
});
});
Check the console (ctrl+shift+j).
Now you can easily access the string. For eg;
console.log('Count: ' + data[k]['count']); //Displays all the count.
Hope you got some idea, You can play around with the JSON object like this and correct me if I'm wrong. Thank You
You can access the properties as below
json[0][0]["count"]
If you want to delete a property use
delete json[0][0]["count"]
Fiddle http://jsfiddle.net/wa99rxgL/
I have some data which I originally stored in a generic Javascript object, with the ID as a key:
{
"7": {"id":"7","name":"Hello"},
"3": {"id":"3","name":"World"},
...
}
However, I discovered that browsers do not guarantee a particular object order when looping through them, so in the above "3" would come before "7". I switched to using an array format like this:
[
{"id":"7","name":"Hello"},
{"id":"3","name":"World"},
...
]
Now, I can loop in the correct order but cannot do fast lookups, e.g. data["3"] without having to loop through the array.
Is there a good way to combine both approaches? I would rather avoid using a separate object for each format, because the object is pretty large (hundreds of elements).
I have run across this problem as well. A solution is to keep an ordered array of keys in addition to the original object.
var objects = {
"7": {"id":"7","name":"Hello"},
"3": {"id":"3","name":"World"},
...
}
var order = [ "3", "7", ... ];
Now if you want the second element you can do this lookup:
var second_object = objects[order[1]];
The ECMA standard does not say anything about the order of the elements in an object. And specifically Chrome reorders the keys when they look like numbers.
Example:
var example = {
"a": "a",
"b": "b",
"1": "1",
"2": "2"
};
if you print this in Chrome will get something like:
{
1: "1",
2: "2",
"a": "a",
"b": "b"
};
It's a little sour .. but life.
You could use the solution Andy linked as well, basically wrapping these two together in one object.
An alternative that I use a lot is a custom map function that allows you to specify the order in which the object is traversed. Typically you will do sorting when you're printing your data to the user so while you loop and create your table rows (for instance) your iterator will pass the rows in the order your sort function specifies. I thought it was a nice idea :)
The signature looks like:
function map(object, callback, sort_function);
Example usage:
map(object, function (row) {
table.add_row(row.header, row.value);
}, function (key1, key2) {
return object[key1] - object[key2];
});
Rather than coding your own, there are off-the-shelf libraries available to provide "as provided" JSON parsing or "consistently sorted" JSON printing for display.
You might well consider either of these:
The 'json-order' package offers parsing, formatting & pretty-printing with stable ordering. This is based on having ordered input.
The 'fast-json-stable-stringify' package offers deterministic formatting based on sorting.
I am trying to figure out if I JSON.Stringify an object like this:
{"m_id":"xxx","record":
{"USER":"yyy","PWD","zzz","_createdAt":
11111."_updatedAt":00000},"state":"valid"}
and then try to JSON.Parse out only the USER and PWD, not have to just call the object, but go through stringify. how would that work?
thanks.
I'm not sure why you're talking about stringifying your object. You'd stringify it if you needed to send the data across a network or something, not when you need to manipulate it in JS.
...how do I extract the strings in {...USER: "aaa", PWD: "zzz"...}?
Assuming you have a variable referring to the object, something like the following (with or without nice line breaks and indenting to make it readable, and with or without quotes around the property names):
var obj = {
"m_id": "xxx",
"record": {
"USER": "yyy",
"PWD" : "zzz",
"_createdAt": 11111,
"_updatedAt": 00000
},
"state": "valid"
};
Then you can access the properties in the nested record object as follows:
console.log( obj.record.USER ); // outputs "yyy"
console.log( obj.record.PWD ); // outputs "zzz"
// etc.
(Note: in your question you had two typos, a comma that should've been a colon in between "PWD" and "zzz", and a dot that should've been a comma in between 11111 and "_updatedAt". There's no way that JSON.stringify() would have produced the string that you showed with those mistakes.)
If you want the strings "USER", "PWD" etc as an array, then use Object.keys.
If you want to iterate them, just use a normal for-in enumeration.
I might have misunderstood the question, but if I think it is what it is then try using
var tmp = JSON.parse(string_to_convert)
this should suffice to convert your string to a proper Javascript Object
Then you can do
for(var index in tmp){
console.log(tmp[index]);
}
and this should list all the keys on the first set of properties. If you want to do a nested thing, then use recursion on the properties. Hope this makes sense...
I have some data which I originally stored in a generic Javascript object, with the ID as a key:
{
"7": {"id":"7","name":"Hello"},
"3": {"id":"3","name":"World"},
...
}
However, I discovered that browsers do not guarantee a particular object order when looping through them, so in the above "3" would come before "7". I switched to using an array format like this:
[
{"id":"7","name":"Hello"},
{"id":"3","name":"World"},
...
]
Now, I can loop in the correct order but cannot do fast lookups, e.g. data["3"] without having to loop through the array.
Is there a good way to combine both approaches? I would rather avoid using a separate object for each format, because the object is pretty large (hundreds of elements).
I have run across this problem as well. A solution is to keep an ordered array of keys in addition to the original object.
var objects = {
"7": {"id":"7","name":"Hello"},
"3": {"id":"3","name":"World"},
...
}
var order = [ "3", "7", ... ];
Now if you want the second element you can do this lookup:
var second_object = objects[order[1]];
The ECMA standard does not say anything about the order of the elements in an object. And specifically Chrome reorders the keys when they look like numbers.
Example:
var example = {
"a": "a",
"b": "b",
"1": "1",
"2": "2"
};
if you print this in Chrome will get something like:
{
1: "1",
2: "2",
"a": "a",
"b": "b"
};
It's a little sour .. but life.
You could use the solution Andy linked as well, basically wrapping these two together in one object.
An alternative that I use a lot is a custom map function that allows you to specify the order in which the object is traversed. Typically you will do sorting when you're printing your data to the user so while you loop and create your table rows (for instance) your iterator will pass the rows in the order your sort function specifies. I thought it was a nice idea :)
The signature looks like:
function map(object, callback, sort_function);
Example usage:
map(object, function (row) {
table.add_row(row.header, row.value);
}, function (key1, key2) {
return object[key1] - object[key2];
});
Rather than coding your own, there are off-the-shelf libraries available to provide "as provided" JSON parsing or "consistently sorted" JSON printing for display.
You might well consider either of these:
The 'json-order' package offers parsing, formatting & pretty-printing with stable ordering. This is based on having ordered input.
The 'fast-json-stable-stringify' package offers deterministic formatting based on sorting.