5

Having a problem trying to sort a JSON object. Basically, people can add products in any random order to our order form, but the order it shows in the summary needs to be how we want them to be positioned (not the order they select them), so thats why I need to sort by 'id' (or we'll sort by a 'pos' field later)

Essentially, I need to sort by the id ascending. 1,2,103 instead of 2,103,1

I seem to be having issues because the index into the individual objects are numbers (or just the fact that they're there...).

I need to do something along the lines of array.sort(function(a,b){ return a.id-b.id }); but I'm presuming that doesn't work because 1, its not an array (its an object), and 2, it has those pesky indexes (that i need for another part of my code)...

Any ideas????

var products = {
 "2": {
 "id": "2",
 "price": "119",
 "quantity": "1",
 "thumb": "img\/store\/comp-08n.png"
 },
 "103": {
 "id": "103",
 "price": "109",
 "quantity": "1",
 "thumb": "img\/store\/basketballhoop.png"
 },
 "1": {
 "id": "1",
 "price": "309",
 "quantity": "1",
 "thumb": "img\/store\/comp-08.png"
 }
};
jcolebrand
16k12 gold badges79 silver badges123 bronze badges
asked May 27, 2011 at 3:27
3
  • Objects are unordered by nature (i.e., there's no "sorting" for a property bag); what's the result you expect? Commented May 27, 2011 at 3:29
  • I think he's using an object as an associative array, instead of a "sparse array", which is what he really wants. Commented May 27, 2011 at 3:40
  • Use an Array of objects. Also, checkout underscore.js. It's pretty nice. Commented May 27, 2011 at 3:45

5 Answers 5

5

How many items do you need in your orders? You can safely sort 10'000 items in a Javascript array without much of speed issues. Why don't you work with a real array instead?

You could even inject custom properties to it, roughly something like

var products = [...];
products.findById = function(id) {
 for (var i=0, len=this.length; i<len; i++) {
 if (id == this[i].id) return this[i];
 }
 return null;
};
alert( products.findById(103).price ); // -> 119

and add predefined sorters like

products.sortById = function() {
 this.sort(function(a,b) {
 return a.id - b.id;
 });
};
products.sortById(); // sort array by product id

** EDIT **

On your PHP side, you might have something like :

$products = array(
 2 => array( 'id' => 2, ... ),
 103 => array( 'id' => 103, ... ),
 1 => array( 'id' => 1, ... ),
);
// get a JSON array
$jsonArray = json_encode(array_values($products));

will return what you need.

** NOTE **

You should not explicitly set indexes when adding new items in your array. Use the array's push function, like

products.push({id:123, price:200.49, quantity:1, thumb:'/path/to/file'});

Removing an item is a bit tricky, however, something like :

products.removeById = function(id) {
 for (var i=0, len=this.length; i<len; i++) {
 if (id == this[i].id) return this.splice(i, 1)[0];
 }
 return null;
};
products.removeById(123); // -> returns the removed element! or null if nothing was removed

See demo here (use Chrome developper tools for console output).

answered May 27, 2011 at 3:31
Sign up to request clarification or add additional context in comments.

7 Comments

Like 20 probably at most... Well, does PHP have a function to dump an associative array into a JS array or would I just make one? At the moment I'm just using json_encode
php has json_encode() which returns a Javascript array if all the indexes are all integers (see the manual)
Thanks a lot for that Yanick, very helpful :) I got it working using your sorter and getting PHP to dump it as an array of objects instead of an object of objects
glad I could help. See the latest edits for more details (if you haven't already done so)
Thanks again! I just noticed the findBy is how I would find the appropriate index rather than setting it (that didnt sink in before lol). Would you say the performance difference between sorting my array at the start into the proper indexes (using a for products.length newarr[products[i].id] = products[i]) so I can access via product[id] is better or worse (speed wise) than running your findById function every single time a product is changed?
|
4

There are two types of collections in JavaScript and in JSON:

  1. key/value map (object) - unordered collection and
  2. Array - index/value map (array) - ordered collection.

By definition only array can be sorted. Use array.

answered May 27, 2011 at 3:32

9 Comments

Then how for example do I access the price of an id without having to know the order of the output? e.g. i cannot just do product[1][1] is price or whatever... :\
@Benno you would just do product[1].price
So my array would look like this? var products = [1:{price:109,name:'Thing'}]; Cos that doesnt seem to work.. its weird, I've never created an array like that before lol :\
@Benno, use this: var a = []; a[1] = {price:109,name:'Thing'}; etc. Most JS implementations use so called sparse arrays so you can create array with "holes".
A "sparse array" would be excatly the same as using an object. It's stored the same, handles the same, length is no longer sensical to use. You're not using the array as an array then.
|
2

recursive solution, doesn't deal with arrays though, javascript

var alphabetizeJSON = function(obj){
 var key,
 array = [],
 stringifiedValuesObj = {},
 jsonKeyVal = "",
 i,
 keyName;
 for (key in obj) {
 if (typeof obj[key] === "object"){
 stringifiedValuesObj[key] = "" + alphabetizeJSON(obj[key]);
 } else {
 obj[key] = obj[key].replace(/\"/gi,'\\\"');
 }
 array.push(key);
 }
 array.sort();
 for (i = 0; i < array.length; i++){
 keyName = array[i];
 jsonKeyVal += '"' + keyName + '": ';
 jsonKeyVal += stringifiedValuesObj[keyName] ? stringifiedValuesObj[keyName] : '"' + obj[keyName] + '"';
 if (i < array.length - 1 ) {
 jsonKeyVal += ',';
 }
 }
 return '{ ' + jsonKeyVal + '}';
};
answered Mar 4, 2014 at 1:15

2 Comments

I got the following error: ReferenceError: orderJSON is not defined
Thanks, fixed. I changed the name of the function
0

Check out JSONArrays. They might be what you need. http://json.org/java/

answered May 27, 2011 at 3:33

Comments

0

Indeed, you should be able to use an array instead of an object for this job, and that will solve a lot of your difficulty.

If you can't do that, you can convert the object into an array to give it ordering... something like this:

var a = []
for (var p in obj) {
 a[+p] = obj[p]
}

If you can't do that, you could dynamically add the information to the page in the order you want (the following is a bad idea)...

for (var i = 0; i < 10000; i++) {
 if (obj[i] !== undefined) {
 add_to_page(obj[i]) //define this somewhere
 }
}
answered May 27, 2011 at 3:39

1 Comment

Hmm, that actually works haha win! Although I realise its kind of wasting resoruces (minimal as they are), so I'll try to convert it to an array first, but if I get fed up I'll do it this way :)

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.