Re-order Json array by key value - javascript

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;
});

Related

Reduce function doesn't seem to work properly

I'm using the function below to extract and create issue objects form all documents of type inspection:
function (doc) {
if(doc.doctype === "inspection"){
for(var i=0; i<doc.issues.length; i++) {
emit(doc.issues[i].id, {id: doc.issues[i].id, status: doc.issues[i].status, date: doc.date});
}
}
}
I'm using the id property of each issue as the key to be able to filter the results later by issue.
This works properly and returns 4 states for states for the same issue with different dates as follows:
{"total_rows":4,"offset":0,"rows":[
{"id":"31cc62d44e1723f4e39757758101a79a","key":"31cc62d44e1723f4e397577581019612","value":
{"id":"31cc62d44e1723f4e397577581019612","status":"pending","date":"2015-09-02"}},
{"id":"31cc62d44e1723f4e39757758101f808","key":"31cc62d44e1723f4e397577581019612","value": {"id":"31cc62d44e1723f4e397577581019612","status":"pending","date":"2015-09-16"}},
{"id":"31cc62d44e1723f4e39757758102f70e","key":"31cc62d44e1723f4e397577581019612","value": {"id":"31cc62d44e1723f4e397577581019612","status":"pending","date":"2015-11-01"}},
{"id":"31cc62d44e1723f4e397577581033cab","key":"31cc62d44e1723f4e397577581019612","value": {"id":"31cc62d44e1723f4e397577581019612","status":"cancelled","date":"2015-12-07"}}
]}
The problem is that I'm trying to run a reduce function to return only the latest issue and I'm unable to loop through all the values.
Although I have 4 rows returned from the map function above the length of the values parameter in the reduce function is 3 using the code below:
function (keys, values, rereduce) {
return values.length
}
{"rows":[
{"key":null,"value":3}
]}
Also when I try to return the values unchanged to see what's going on I noticed that two of the values have been grouped together as follows:
{"rows":[
{"key":null,"value":[
[{"id":"31cc62d44e1723f4e397577581019612","status":"pending","date":"2015-11-01"},
{"id":"31cc62d44e1723f4e397577581019612","status":"pending","date":"2015-09-02"}],
[{"id":"31cc62d44e1723f4e397577581019612","status":"cancelled","date":"2015-12-07"}],
[{"id":"31cc62d44e1723f4e397577581019612","status":"pending","date":"2015-09-16"}]]}
]}
Notice that the first two objects have been grouped together in a single array.
I'm really confused and I think it's a simple task but I can't figure out what I'm missing here..
I tried to loop through the values param to compare the date attribute, but that didn't work.
I also used the code below to search for the id attribute recursively but it also failed:
function (keys, values, rereduce) {
var res = [];
function extractVal(obj) {
if(obj.id) {
res.push(obj.id);
}else {
for(key in obj) {
extractVal(obj[key]);
}
}
}
extractVal(values);
return res;
}
Ok, This is what I figured out and please correct me if I'm wrong.
The reduce function runs several times with the rereduce value = false, and finally it runs on last time with the rereduce value = true.
So if I just returned the values array as it is in the condition where rereduce is false I will get an array of those returned arrays as the values parameter in the final step where the rereduce = true.
And therefore to extract the objects that were returned in the map function I need to run a nested loop as follows:
function (keys, values, rereduce) {
var arr=[];
if(rereduce){
for(var i=0; i<values.length; i++) {
for(var j=0; j<values[i].length; j++) {
arr.push(values[i][j]);
}
}
return arr;
} else{
return values;
}
}
And finally instead of just returning the arr parameter I will process it to filter whaterver should be returned by the reduce function.

Loop through json object and sort in order

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... :-)

Merge array into a single array

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

Sorting a multi-dimensional JSON object in Javascript

I tried finding an answer to this on here, but kept coming up with real simplistic examples, so here goes:
I am pulling a photoset list from Flickr's API, and it needs to be in javascript. Anyhow, their response is unlike most others places the value to sort within a sub-object like so:
"photoset":[
{..."photos":"15", "videos":0, "title":{"_content":"Shocktoberfest 2012"}, "description":{"_content":""}, "needs_interstitial":0, "visibility_can_see_set":1, "count_views":"0", "count_comments":"0", "can_comment":0, "date_create":"1351829136", "date_update":"1351829309"}
...
...
...
]
How can I sort on the title for instance, when the value is within in a sub-object like it is?
You could provide a callback to the Array.sort and return the usual -1, 0, 1 for sorting:
some_response.photoset.sort(function(a, b){
return a.title._content.localeCompare(b.title._content);
});
Not sure either but , I would begin to figure it out with a for/in statement loop...
var photoObjects= {};
for(k in initialObject){
photoObjects[k] = initalObject.photoset[0][k];
console.log(photoObjecs[k]);
}
Javascript allows you to pass a function as parameter to the Arrays sort function,
you could just write a simple helper function to sort an array with object after there titles
var arr = [
{title:"A"},
{title:"F"},
{title:"B"}
];
function sortarr (arr,item) {
arr.sort(function (a,b) {
if (typeof a == "object" && typeof b == "object" ) {
console.log(a[item]);
if ( a[item] < b[item] )
return -1;
if ( a[item] > b[item] )
return 1;
return 0;
}
});
return arr;
}
console.log(JSON.stringify(sortarr(arr,"title")));
Here is an example on jsbin

Javascript sort multi-dimensional array - a complete example?

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.

Categories