Currently I have a small piece of code which loops through a json object:
for (var key in json_object) {
if (json_object.hasOwnProperty(key)) {
var value = key; //e.g. 50_100, 1000_2000, 20_50 etc
}
}
I'm going to be outputting these values into a list later on. But the problem is that these values aren't in any order right now.
I'd like to be able to have these values sorted out in order. So my question is, is this possible and if so how?
Thanks!
In javascript, object properties are not guaranteed a specific order, so if you want to maintain order, you would likely need to write the object properties into an array of objects.
That could look like this:
var object_array = [];
// map properties into array of objects
for (var key in json_object) {
if (json_object.hasOwnProperty(key)) {
object_array.push({
'key': key;
'value': value;
});
}
}
// sort array of objects
object_array.sort(function(a,b) {
// note that you might need to change the sort comparison function to meet your needs
return (a.value > b.value);
}
After reading all solutions, I realized my solution was wrong. Object.keys is good for getting an array of keys only, so Mike Brant's solution is correct, although a little fix is needed since value is not a variable there. Finally here's a fixed solution based on his solution + the requested sorting from the comments:
var arr = [];
for (var key in json_object) {
if (json_object.hasOwnProperty(key)) {
arr.push({
'key': key;
'value': json_object[key];
});
}
}
// this will sort by the first part of the string
arr.sort(function(a, b) {
return a.key.split('_')[0] - b.key.split('_')[0];
}
Hope this helps... :-)
Related
If this were .NET, I'd ask how to convert List<List<MyClass> to List<MyClass>. However, I'm not very good with javascript and don't know how to ask that as a question using Javascript terminology!
My javascript object comes through like
And is created as:
js_datasets.push({
"DataItem0": {
lzabel: "This",
data: [[1408710276000, null],[1408710276000, 15]]
},
"DataItem1": {
lzabel: "That",
data: [[1408710276000, null],[1408710276000, 15]]
},
});
js_datasets.push({
"DataItem22": {
lzabel: "And other",
data: [[1408710276000, null],[1408710276000, 5]]
},
"DataItem23": {
lzabel: "And lastly",
data: [[1408710276000, null],[1408710276000, 1]]
},
});
Each object is the same "type" (if it matters).
I'd like to create a single list but I am failing to do so. My efforts are
var myDataSet = []; //this is the results of what I want, ideally as a single list
for (var i = 0; i < js_datasets.length; i++) {
if (i==0) {
myDataSet.push(js_datasets[i]);
}
else {
myDataSet.concat(js_datasets[i]);//does nothing
myDataSet.join(js_datasets[i]);//does nothing
}
...more logic
As you can see with the above, I've tried using push, concat and join.
If I update the code to only use push (and never use concat and join) then I get all the values I want, but again, as an array within an array.
Using concat and join do not add to the list.
So, if we can assume the 12 items in the array (pictured) all contain 10 items, I'd like to have a single list of the 120 items!
How can I simply convert this multidimension array (is it multidimension) to a single dimension array.
This will be a bit complicated, as the items in your Array js_datasets are not Arrays, but a more generic Object. This means you can't assume the keys will be in order if you try to read them
Lets write some helper functions to account for this;
function dataItemCollectionToArray(o) {
var keys = Object.keys(o);
// assuming no non-DataItem keys, so next line commented out
// keys = keys.filter(function (e) {return e.indexOf("DataItem") === 0;});
keys.sort(function (a, b) { // ensure you will get the desired order
return +a.slice(8) - +b.slice(8);
});
return keys.map(function (e) {return o[e];});
}
Now you can loop over js_datasets performing this conversion
var myDataSet = [], i;
for (i = 0; i < js_datasets.length; ++i) {
// assuming no gaps, if you need to add gaps, also find min, max indices
// in `dataItemCollectionToArray`, and check them in each iteration here
myDataSet.push.apply(myDataSet, dataItemCollectionToArray(js_datasets[i]));
}
Please note that Object.keys and Array.prototype.map may require polifills if you wish to support old browsers, i.e. IE<=8
An easier solution however, may be to re-write how js_datasets is constructed so that the Objects you are pushing are more Array-like or indeed pushing true Arrays, perhaps with a couple extra properties so you know the offset for the first index. This would mean you can use flatten methods that you'll find around the internet
{
"TR":{
"total_fans":1848,
"country_name":"Turkey"
},
"US":{
"total_fans":1097,
"country_name":"United States"
},
"DE":{
"total_fans":915,
"country_name":"Germany"
},
"MX":{
"total_fans":1148,
"country_name":"Mexico"
},
"RS":{
"total_fans":359,
"country_name":"Serbia"
},
"IT":{
"total_fans":798,
"country_name":"Italy"
}
}
I would like to sort this based on fans. For instance, in this case it should be "TR", "MX", "US"... and so on using JS and Underscore if that helps.
Thanks!
JavaScript objects are unordered, so you won't be able to sort or otherwise define a specific order.
You could convert the properties to an Array, and sort that instead, but that's about as close as you'll get.
Since it seems you want to sort by number of fans, you can do this.
Object.keys(myObject)
.sort(function(a,b) {
return myObject[a].total_fans - myObject[b].total_fans;
}).forEach(function(key) {
console.log(myObject[key]);
});
To support IE8 and lower, you'll need patches for Object.keys and Array.prototype.forEach.
And as Bruce Lim noted, this is an ascending sort. To descend, swap the operands of the - operator after the return.
return myObject[b].total_fans - myObject[a].total_fans;
No underscore is necessary if you don't care about IE < 9. Given your structure being in a variable obj:
var sorted = Object
.keys(obj)
.map(function(key) {
// Put the country in the item?
obj[key].country = key;
return obj[key];
})
.sort(function(a, b) {
if (a.total_fans > b.total_fans) {
return -1;
} else if (b.total_fans > a.total_fans) {
return 1;
}
return 0;
});
This will give you an Array sorted with the items having the most fans being first, and the country code added to each item in case you need that (omit if unnecessary).
Try sorting with an array:
var array = [];
// copy object to array
for (var x in yourObject) array.push([x, yourObject[x].total_fans]);
// sort array
array.sort(function(item1, item2) { return item1[1] - item2[1] });
// now get the keys
var keys = [];
for (var i = 0; i < array.length; i ++) keys.push(array[i][0]);
// keys = ["RS", "IT", "DE", "US", "MX", "TR"]
Note that the key-getting step could be easier with map if you don't care about old IEs.
UPDATE: Thanks to a heated but useful exchange with Doorknob, I realized that he had an excellent point about being careful about modifying Object.prototype. I modified the answer to make the extension of Object.prototype less intrusive by making the new method non-enumerable. Thanks, Doorknob!
UPDATE 2: I realize now that the OP's wisely selected correct answer has the right of it. Object.keys does exactly what my ownProps method (see below) does, and it's a standard (though you still have to polyfill in IE8). I would just delete this answer since cookie monster nailed it, but I think this is a useful discussion and even though ownProps is redundant with Object.keys, it might teach someone...something.
I wrote a convenience function called ownProps which returns all the property names of an object (excluding properties in the prototype chain). It's a more functional way of doing what Doorknob is suggesting above:
// retrieves all of the properties of an object as an array,
// omitting properties in the prototype chain; note that we use
// Object.defineProperty so we can make this non-enumerable, thereby
// making a safer modification of Object.prototype
Object.defineProperty(Object.prototype,'ownProps',{
enumerable: false,
value: function() {
var props = []; for( var prop in this ) {
if( this.hasOwnProperty( prop ) ) props.push( prop );
}
return props;
}
});
Armed with this, you can sort your object using a custom sort function:
var obj = {"TR":{"fans":1848,"country_name":"Turkey"}/*...*/}
var sortedKeys = obj.ownProps().sort(function(a,b){
return obj[a].fans - obj[b].fans;
});
Solution: http://jsfiddle.net/az7XN/
lets say that whole your object of fans is a fansObj:
for(prop in fansObj){
console.log(prop, fansObj[prop]);
}
output example: TR, {"fans":1848,"country_name":"Turkey" }
before for circle declare array variable and push there each obj:
var arr = [];
for(prop in fansObj){
console.log(prop, fansObj[prop]);
arr.push(fansObj[prop]);
}
then sort:
arr.sort(function(a,b){parseInt(b['total_fans'],10) - parseInt(a['total_fans'])});
parseInt(obj,10) will accept convert object as decimal to integer.
Now you have sorted array (depending on comparison inside sort function (a-b=desc or b-a=asc)).
Used function:
for..in
Array.prototype.sort()
parseInt()
This should be pretty easy but I'm a little confused here. I want to fill this object:
var obj = { 2:some1, 14:some2, three:some3, XX:some4, five:some5 };
but in the start I have this:
var obj = {};
I´m making a for but I don't know how to add, I was using push(), but is not working. Any help?
You can't .push() into a javascript OBJECT, since it uses custom keys instead of index. The way of doing this is pretty much like this:
var obj = {};
for (var k = 0; k<10; k++) {
obj['customkey'+k] = 'some'+k;
}
This would return:
obj {
customkey0 : 'some0',
customkey1 : 'some1',
customkey2 : 'some2',
...
}
Keep in mind, an array: ['some1','some2'] is basicly like and object:
{
0 : 'some1',
1 : 'some2'
}
Where an object replaces the "index" (0,1,etc) by a STRING key.
Hope this helps.
push() is for use in arrays, but you're creating a object.
You can add properties to an object in a few different ways:
obj.one = some1;
or
obj['one'] = some1;
I would write a simple function like this:
function pushVal(obj, value) {
var index = Object.size(obj);
//index is modified to be a string.
obj[index] = value;
}
Then in your code, when you want to add values to an object you can simply call:
for(var i=0; i<someArray.length; i++) {
pushVal(obj, someArray[i]);
}
For info on the size function I used, see here. Note, it is possible to use the index from the for loop, however, if you wanted to add multiple arrays to this one object, my method prevents conflicting indices.
EDIT
Seeing that you changed your keys in your questions example, in order to create the object, you can use the following:
function pushVal(obj, value, key) {
//index is modified to be a string.
obj[key] = value;
}
or
obj[key] = value;
I'm not sure how you determine your key value, so without that information, I can't write a solution to recreate the object, (as is, they appear random).
I have a contact list that is returned to me in this very long form. It is getting returned Based on order of entry (the field outside the first set of brackets, indented). The problem I'm having is I want it to order alphabetically by displayName. Since that is in it's own array inside of the main one I'm having trouble getting the full array to reorder by it. Can anyone figure this out? Thanks. Oh and it's got to be done in JS.
{
"0":
{"id":1,"rawId":null,"displayName":"Person 1","name":null,"nickname":null,"phoneNumbers":[{"type":"mobile","value":"phonenumb53534r","id":0,"pref":false}],"emails":null,"addresses":null,"ims":null,"organizations":null,"birthday":null,"note":null,"photos":null,"categories":null,"urls":null},
"1":
{"id":2,"rawId":null,"displayName":"Person 2","name":null,"nickname":null,"phoneNumbers":[{"type":"mobile","value":"phonenumber535345","id":0,"pref":false}],"emails":null,"addresses":null,"ims":null,"organizations":null,"birthday":null,"note":null,"photos":null,"categories":null,"urls":null},
"2":
{"id":3,"rawId":null,"displayName":"Person 3","name":null,"nickname":null,"phoneNumbers":[{"type":"mobile","value":"phonenumber47474","id":0,"pref":false}],"emails":null,"addresses":null,"ims":null,"organizations":null,"birthday":null,"note":null,"photos":null,"categories":null,"urls":null}, goes on for a couple hundred rows
Objects in JavaScript are not ordinal by nature. If you have an array, you can work with that. Otherwise, you have to convert the outer part of the object into an array yourself:
var arrayOfObj = [];
for (item in obj) {
if (obj.hasOwnProperty(item)) {
arrayOfObj.push(obj[item]);
}
}
If you can do that before you even get the JSON, so much the better. Once you have that, you can just use the normal array .sort method
arrayOfObj.sort(function (a, b) {
if (a.displayName < b.displayName) {
return -1;
}
else if (a.displayName > b.displayName) {
return 1;
}
return 0;
});
http://jsfiddle.net/ZcM7W/
You'll need to parse that responseText into JSON. But since it's returned as an object literal you'll have to convert it to an array. Then you can sort it with a custom comparator function.
var json = JSON.parse(response),
data = [];
for (key in json) {
data.push(json[key]);
}
data.sort(function (a, b) {
return a.displayName > b.displayName;
});
I'm no Javascript expert and I'm having problems trying to glue together the various nuggets I find here and elsewhere regarding multi-dimensional arrays and sorting and wondered if someone could help me with a complete example?
I have managed to get to the point that I can populate a localStorage with data read in via Ajax.
The format of the rows is ...
(msgXXX) (Key1:Value1|Key2:Value2|Key3:Value3|...etc)
where
(msgXXX) is the localStorage key; and
(Key1:Value1|Key2:Value2|Key3:Value3|...etc) is the single concatenated localStorage data string
What I want to be able to do is convert all this to a multi-dimensional array to which I can apply various sorts. For example, one of the Keys is called "Timestamp" and the value is an integer representing seconds since the Unix epoch. I would like to sort all rows based on this Timestamp value (in descending order - ie latest first). Right now the dataset is just over 600 rows.
I'm comfortable I can do the extraction and slicing and dicing to get the data out of the localStorage, but I'm not even sure what I'm aiming for with regards to populating an array and then setting up the sort.
Can someone point me in the right direction?
You can go with something like this:
function create(line) {
var tokens = line.split("|");
var obj = {};
for (var i = 0; i < tokens.length; i++) {
tokens[i] = tokens[i].split(":");
obj[tokens[i][0]] = tokens[i][1];
}
return obj;
}
var arr = [];
for (....) { // iterate over the input that each line is of key/value format
arr.push(create(line));
}
function timestampSort(a, b) {
if (a == b)
return 0;
return a.timestamp < b.timestamp ? -1 : 1;
}
// to sort by timestamp
arr.sort(timestampSort);
This code creates an object per key/value line, in the format you gave. The object will have the keys as attributes. All of those objects are being pushed into an array, which is then being sorted by passing a compare function to the native sort method of array.
You can of course make as many compare functions as you want, each comparing by a different attribute/criteria.
You can read more about the sort method here: http://www.w3schools.com/jsref/jsref_sort.asp
EDIT
The sort method both changes the array itself and returns the array, so doing something like:
console.log(arr.sort(timestampSort));
Will both change the actual array and return it, and so the console.log will print it.
If you don't want to change the original array and have a copy of it that will get sorted you can:
var arr2 = arr.slice();
arr2.sort(timestampSort);
As for the keys in the array, what I wrote was intended to work only with this part of the line: Key1:Value1|Key2:Value2|Key3:Value3|...etc
So, to add support for the entire format, here's the modification:
function create(line) {
var parts = line.match(/^\(msg(\d+)\) \((.+)\)$/);
var tokens = parts[2].split("|");
var obj = { msgID: parts[1] };
for (var i = 0; i < tokens.length; i++) {
tokens[i] = tokens[i].split(":");
obj[tokens[i][0]] = tokens[i][1];
}
return obj;
}
If you apply this to the example you gave you'll get this:
arr is: [{
msgID: XXX,
Key1: Value1,
Key2: Value2,
Key3: Value3
}]
Hope this clears things for you.