11

I have an array with arrays in it, where I want to sort the outer arrays based on values in a specific column in the inner.

I bet that sounded more than a bit confusing, so I'll skip straight to an example.

Initial data:

var data = [
  [
    "row_1-col1",
    "2-row_1-col2",
    "c-row_1-coln"
  ],
  [
    "row_2-col1",
    "1-row_2-col2",
    "b-row_2-coln"
  ],
  [
    "row_m-col1",
    "3-row_m-col2",
    "a-row_m-coln"
  ]
];

Sort data, based on column with index 1

data.sortFuncOfSomeKind(1);

where the object then would look like this;

var data = [
  [
    "row_2-col1",
    "1-row_2-col2",
    "b-row_2-coln"
  ],
  [
    "row_1-col1",
    "2-row_1-col2",
    "c-row_1-coln"
  ],
  [
    "row_m-col1",
    "3-row_m-col2",
    "a-row_m-coln"
  ]
];

Sort data, based on column with index 2

data.sortFuncOfSomeKind(2);

where the object then would look like this;

var data = [
  [
    "row_m-col1",
    "3-row_m-col2",
    "a-row_m-coln"
  ],
  [
    "row_2-col1",
    "1-row_2-col2",
    "b-row_2-coln"
  ],
  [
    "row_1-col1",
    "2-row_1-col2",
    "c-row_1-coln"
  ]
];

The big Q

Is there an existing solution to this that you know of, or would I have to write one myself? If so, which would be the easiest sort algorithm to use? QuickSort?

_L

ptrn
  • 4,902
  • 6
  • 28
  • 30
  • 2
    possible duplicate of [Sorting objects in an array by a field value in JavaScript](http://stackoverflow.com/questions/1129216/sorting-objects-in-an-array-by-a-field-value-in-javascript), [Javascript: How to sort an array of records by values in one of the fields?](http://stackoverflow.com/questions/1689679/javascript-how-to-sort-an-array-of-records-by-values-in-one-of-the-fields) – outis May 08 '10 at 11:33

3 Answers3

16

Array#sort (see section 15.4.4.11 of the spec, or MDC) accepts an optional function parameter which will be used to compare two entries for sorting purposes. The function should return -1 if the first argument is "less than" the second, 0 if they're equal, or 1 if the first is "greater than" the second. So:

outerArray.sort(function(a, b) {
    var valueA, valueB;

    valueA = a[1]; // Where 1 is your index, from your example
    valueB = b[1];
    if (valueA < valueB) {
        return -1;
    }
    else if (valueA > valueB) {
        return 1;
    }
    return 0;
});

(You can obviously compress that code a bit; I've kept it verbose for clarity.)

T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875
8

Here is a solution not needing a separate variable to contain the index

var arr = [.....]
arr.sort((function(index){
    return function(a, b){
        return (a[index] === b[index] ? 0 : (a[index] < b[index] ? -1 : 1));
    };
})(2)); // 2 is the index

This sorts on index 2

Sean Kinsey
  • 37,689
  • 7
  • 52
  • 71
  • 1
    You should change that `=` to `===`. Comparisons don't like to be mistaken for assignments. – awgy May 08 '10 at 12:49
  • Well, change it to `==` or `===` depending on your needs. – T.J. Crowder May 08 '10 at 13:12
  • yep, a small bug there - fixed now – Sean Kinsey May 08 '10 at 15:06
  • I tend to suggest `===` as a result of some advice from Douglas Crockford: "It is almost always better to use the `===` and `!==` operators. The `==` and `!=` operators do type coercion. In particular, do not use `==` to compare against falsy values." But I agree that there are instances where the type coercion may be desired. (See: http://javascript.crockford.com/code.html) – awgy May 08 '10 at 16:05
  • @awgy: In this case, though, it probably makes more sense to use `==` -- because `>` and `<` do type conversion, too, so if you use `===` in his code above, you'll return `1` incorrectly if the values are `==` but not `===`. – T.J. Crowder May 08 '10 at 17:00
  • But in this case all the values are strings, so it really does't matter. And that > and < has to coerce as its pretty hard say which is 'before' the other between the string "2" and the number 3. – Sean Kinsey May 08 '10 at 17:10
  • That was an excellent solution. Fixed my issue programmagically! – Ken Ingram Apr 26 '20 at 14:15
2

Here used to be a sort implementation that returned the result of a simple x<y comparison. This solution is disencouraged and this post is left only to preserve the ensuing discussion.

David Hedlund
  • 128,221
  • 31
  • 203
  • 222
  • D'oh. I didn't know you could just return x[a] > y[a] for a comparison value like that. That'll save me a few lines of code. – awgy May 08 '10 at 11:28
  • @David: You're returning `true` or `false`. You need to return -1, 0, or 1. (I did check, in case there was some Really Cool Thing I was missing, but the above fails to sort correctly in all cases.) – T.J. Crowder May 08 '10 at 11:32
  • @T.J.Crowder: when i run that code, it correctly outputs 'one - three - two', 'two - three - one', 'one - three - two'. just the output you'd expect from an alphabetical sort. is that not the result you're seeing? http://jsbin.com/ovoze3 – David Hedlund May 08 '10 at 11:44
  • @T.J. Crowder: furthermore: mine - http://jsbin.com/ovoze3/edit yours - http://jsbin.com/ovoze3/2/edit . hit "preview" > "go" in them, and they'll produce exactly the same result – David Hedlund May 08 '10 at 11:48
  • @David: That's not the result I'm seeing (and perhaps more to the point, isn't the result I *should* see). My original test was on Chrome ("two three one", "three one two", "one two three"). It also doesn't work on IE7 ("one three two", "two one three", "two one three"). It does *seem* to work on Firefox, which I'm taking as a side-effect of how it implements `sort` (e.g., it just happens to flip at a time when the others done) rather than a reliable interpretation of the code. Running your jsbin tests on Chrome shows the same rseult, with mine showing the correct result. – T.J. Crowder May 08 '10 at 12:20
  • 1
    @David: See section 15.4.4.11 of the 5th ed. spec (http://www.ecma-international.org/publications/standards/Ecma-262.htm): The compare function *"...should be a function that accepts two arguments x and y and returns a negative value if x < y, zero if x = y, or a positive value if x > y."* and section 11.8.5 (about `>`): *"The comparison...produces true, false, or undefined (which indicates that at least one operand is NaN)."* Returning `true` or `false` out of the function therefore results in undefined behavior, and as the function *must* have three possible outcomes, incorrect behavior. – T.J. Crowder May 08 '10 at 12:25
  • Well, bleh then. I had typed up a solution differentiating between -1/0/1, but saw I collided with @David and thought his solution was more elegant. So, I deleted mine. I guess I should've left mine up. And here I was thinking I'd been missing out on some weird JavaScript concept. – awgy May 08 '10 at 12:48
  • @T.J. Crowder: curious, i ran all my tests on chrome 5, and opened up firefox just for verification. still seeing the same results in chrome, but i'll write that off as an implementation curiosity, then. thanks for the pointers – David Hedlund May 08 '10 at 13:12
  • @David: Weird! I'm really shocked to hear it worked in Chrome 5 beta. My tests were in Chrome 4.1. (And again, it *shouldn't* work, regardless, which is the more salient point.) – T.J. Crowder May 08 '10 at 13:14
  • this is due to get further downvoted i guess, but i'd rather not delete it, as the discussion that followed seems worth saving... – David Hedlund May 08 '10 at 14:47
  • @David: I expect if you edit it, it won't get downvoted further. – T.J. Crowder May 08 '10 at 14:56
  • The answer to this is probably that true/false with type coercion corresponds to 0/1, that is, two of the expected values. Now, depending on the sort algorithm used, and the array to be sorted, these two results (equal or x>y) might actually give the correct result. And as different browsers use different algorithms for sorting, I'm guessing this is whats happening here.. – Sean Kinsey May 08 '10 at 17:02
  • I read this and was like "no chance that works...." and it literally just works...that's awesome, thanks so much, you saved me from implementing my own sort, up-voted :). – Trevor Hart Sep 12 '16 at 21:20
  • @Trevor: You don't have to implement your own sort, but please use the accepted answer. Read the comments to this answer for rationale :-) – David Hedlund Sep 13 '16 at 16:27