...

# Javascript sort not working for my multidimensional array

saltoceana
10-11-2011, 07:51 AM
I have the following array called 'datacontent' that have the following data:
(4, RX33, )
(3, RX54, )
(102, RX44, )
(1, R100, Retail Branch 100)
(2, RX12, )
(100, RX55, )

I want them to be sorted into this order:
(1, R100, Retail Branch 100)
(2, RX12, )
(3, RX54, )
(4, RX33, )
(100, RX55, )
(102, RX44, )

But it is always not sorted and it will give me as follows:
(2, RX12, )
(3, RX54, )
(4, RX33, )
(100, RX55, )
(102, RX44, )
(1, R100, Retail Branch 100)

My code is as follows:

function sortby(i) {
return function(a,b){a = a[i];b = b[i];return a.toLowerCase() == b.toLowerCase() ? 0 : (a.toLowerCase() < b.toLowerCase() ? -1 : 1)}
}
datacontent.sort(sortby(1));

Appreciate any help.

siberia-man
10-11-2011, 07:57 AM
Function sortby should accept two arguments meaning two items of sorted array.This function is sorting criterion and should be passed as an argument to the Array#sort method. Look below

function sortby(a, b)
{
// define here how you want to sort items
};

datacontent.sort(sortby);

venegal
10-11-2011, 06:23 PM
First of all, disregard that previous reply — your general setup is ok.

Second, you're using it wrong: sortby returns a compare function that compares the arrays by their entries with index i. You want to compare them by index 0 (the first array element), so it has to be sortby(0), and not sortby(1). That said, I don't believe the result you posted. It's supposed to be ordered alphanumerically by those "RX" strings, but the result you posted isn't.

Third, alphanumerical ordering won't do you any good for those numbers, because 100 will come before 2. You will want to check whether the index you are comparing holds a number or a string, and then do the appropriate type of comparison:

var datacontent = [
[4, 'RX33'],
[3, 'RX54'],
[102, 'RX44'],
[1, 'R100'],
[2, 'RX12'],
[100, 'RX55']
];

function sortby(i) {
return function (a, b) {
a = a[i];
b = b[i];
if (typeof a == 'number') {
return a - b;
}
else {
return a == b ? 0 : (a < b ? -1 : 1);
}
};
}

datacontent.sort(sortby(0));
console.log(datacontent);

As you can see, this is assuming that the first entry of those arrays is really a number, and not a string containing a number, which isn't clear from what you have posted. If those are strings containing numbers, you have to replace that typeof check with a regexp.

siberia-man
10-11-2011, 08:48 PM
Hi venegal,

Could you be so kind as to point, please, which part of my post brought you to the decision to disregard my reply? Let's learn these links from MSDN and MDN, respectively:

http://msdn.microsoft.com/en-us/library/fcatw4ty%28v=VS.90%29.aspx
https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/sort

Accordingly these docs my description is correct although it might be not considered to complete. Taking in account the function used by the topic starter is a closure, returning another function it is correct too, but he should pass 0 to refer to the first item of an inner array.

But I'd like to point your attention that your function is not good because it checks a type of arguments each time when it is called. Think, each time when the function is called! This is not good practice. More over this is not good to offer such kind of code to others.

venegal
10-12-2011, 01:22 AM
siberia-man: My advice to disregard your reply only meant that it doesn't help solve the actual problem. There's no doubt that as an advice how to generally use a compare function with Array.sort it's correct, but for the actual issue, it's confusing: the way the sortby function is set up in the OP, it definitely should not accept two parameters, and the actual issues are not addressed.

As for the type checking within the compare function: I'm just working with the code the OP posted here. It's obviously set up to allow for ordering by arbitrary array index, and there's no way to do that except by checking the type in the compare function. The check could be done on the outside, but as soon as it's done there, the whole closure setup allowing the outside code to be agnostic of what's inside those arrays would be useless. Since the OP's code is well written overall, I just assumed it's by design that the outside code shouldn't have to care about what's inside the arrays.

Old Pedant
10-12-2011, 04:29 AM
This is confusing:

return function (a, b) {
a = a[i];
b = b[i];

Cute, but confusing.

Just to clarify it, I would have written:

return function (arrA, arrB) {
var a = arrA[i];
var b = arrB[i];

But...

But I don't think the answer is complete, at all.

Or, rather, it *MIGHT* not be, depending on the data given.

Suppose this was the data, instead:

var datacontent = [
[4, 'RX33'],
[3, 'RX54'],
[102, 'RX44'],
[1, 'R100'],
[2, 'RX12'],
[100, 'RX55'],
[3, 'RX22'],
[3, 'RX95']
];

The three elements with first subelement = 3 won't come out in second subelement order, which is what I would assume we should expect.

So I'd just write it dirt simple:

function sortDatacontent( arrA, arrB )
{
var chk = arrA[0] - arrB[0];
if ( chk != 0 ) return chk;
return arrA[1] == arrB[1] ? 0 : (arrA[1] < arrB[1] ? -1 : 1);
}
datacontent.sort( sortDatacontent );

Not as general/flexible, but will do the job an in very little code.

venegal
10-12-2011, 04:34 AM
But I don't think the answer is complete, at all.

Or, rather, it *MIGHT* not be, depending on the data given.

I sort of assumed that the integer is a unique ID, but you're right, we don't know that.

Old Pedant
10-12-2011, 04:40 AM
Yep, it's one of the joys of forum postings. You never know if you've got the whole story or not. <grin/>

So here's a fun challenge for you: Write a sort function that works for non-homogeneous multi-dimensional arrays of any number of dimensions. Be sure to handle the case where two values being compared are, say, date and string. Or number and boolean. Or...

venegal
10-12-2011, 05:39 AM
So here's a fun challenge for you: Write a sort function that works for non-homogeneous multi-dimensional arrays of any number of dimensions. Be sure to handle the case where two values being compared are, say, date and string. Or number and boolean. Or...

Interesting. The function comparing the two arrays, I'd probably write like this:

// Compare function for sorting multi-dimensional arrays
function multiDimCompare(a, b) {
// Remember current array index
var i = 0;
return (function recursiveCompare() {
// If one of the two arrays doesn't have any more entries before a conclusion
// has been reached, array length will be used for sorting
if (i >= Math.max(a.length, b.length)) return a.length - b.length;
// Compare the actual entries
var difference = compare(a[i], b[i++]);
// If equal, try again with next array index, else return difference
return difference == 0 ? recursiveCompare() : difference;
}());
};

As for the actual compare function, you'd have to know the business logic in order to decide how to compare, say, a Date and a String. I realize that this challenge has been more of a joke, though, so I'll leave the implementation details to you.

Old Pedant
10-12-2011, 06:02 AM
I only tossed in Date because it's built into the JS language. I'd probably just compare the two getTime() values [assuming both are dates]. The heterogenous part is what would make a general solution tough, if not impossible.

I was actually serious about the idea. I was thinking of maybe creating a prototype where the user could specify all the rules for comparisons (or opt to take the defaults, of course).

saltoceana
10-12-2011, 06:13 AM
Thank you everyone for such helpful response.

Hi Old Pedant,
Just to point out one thing, the entry [1, 'R100'] should be [1, R100, Retail Branch 100] as it is the only array that contain 3 elements.

So here's a fun challenge for you: Write a sort function that works for non-homogeneous multi-dimensional arrays of any number of dimensions. Be sure to handle the case where two values being compared are, say, date and string. Or number and boolean. Or...

... as it do help to tackle all kinds of sorting of two values.

Hi Venegal,
I used your first code and modify it as shown ...

function sortby(i) {
return function (a, b) {
a = parseInt(a[i]);
b = parseInt(b[i]);
if (typeof a == 'number') {
return a - b;
}
else {
return a == b ? 0 : (a < b ? -1 : 1);
}
};
}

datacontent.sort(sortby(0));
console.log(datacontent);

... and now it is working awesome. :thumbsup:

venegal
10-12-2011, 06:28 AM
I only tossed in Date because it's built into the JS language. I'd probably just compare the two getTime() values [assuming both are dates]. The heterogenous part is what would make a general solution tough, if not impossible.

I was actually serious about the idea. I was thinking of maybe creating a prototype where the user could specify all the rules for comparisons (or opt to take the defaults, of course).

I'm not sure comparing different types makes a whole lot of sense for sorting (except maybe numbers and number-strings). If the types are different, they should probably just be sorted by type. Also, passing those comparison rules to that prototype function sounds exactly like passing a custom compare function to Array.sort to me, so I don't really see the advantage.

Btw, comparing two Dates is no problem at all using standard comparison operators, so there's no need for getTime(), or, for that matter, any custom compare function.