JavaScript asort
Sort an array and maintain index association
1 2 3 4 56 7 8 9 1011 12 13 14 1516 17 18 19 2021 22 23 24 2526 27 28 29 3031 32 33 34 3536 37 38 39 4041 42 43 44 4546 47 48 49 5051 52 53 54 5556 57 58 59 6061 62 63 64 6566 67 68 69 7071 72 73 74 7576 77 78 79 8081 82 83 84 8586 87 88 89 9091 92 93 94 9596 97 98 99 100101 102 103 104 105106 107 108 109 110111 112 113 114 115116 | function asort (inputArr, sort_flags) { // Sort an array and maintain index association // // version: 1008.1718 // discuss at: http://phpjs.org/functions/asort // + original by: Brett Zamir (http://brett-zamir.me) // + improved by: Brett Zamir (http://brett-zamir.me) // + input by: paulo kuong // + improved by: Brett Zamir (http://brett-zamir.me) // + bugfixed by: Adam Wallner (http://web2.bitbaro.hu/) // % note 1: SORT_STRING (as well as natsort and natcasesort) might also be // % note 1: integrated into all of these functions by adapting the code at // % note 1: http://sourcefrog.net/projects/natsort/natcompare.js // % note 2: The examples are correct, this is a new way // % note 2: Credits to: http://javascript.internet.com/math-related/bubble-sort.html // % note 3: This function deviates from PHP in returning a copy of the array instead // % note 3: of acting by reference and returning true; this was necessary because // % note 3: IE does not allow deleting and re-adding of properties without caching // % note 3: of property position; you can set the ini of "phpjs.strictForIn" to true to // % note 3: get the PHP behavior, but use this only if you are in an environment // % note 3: such as Firefox extensions where for-in iteration order is fixed and true // % note 3: property deletion is supported. Note that we intend to implement the PHP // % note 3: behavior by default if IE ever does allow it; only gives shallow copy since // % note 3: is by reference in PHP anyways // - depends on: strnatcmp // - depends on: i18n_loc_get_default // * example 1: data = {d: 'lemon', a: 'orange', b: 'banana', c: 'apple'}; // * example 1: data = asort(data); // * results 1: data == {c: 'apple', b: 'banana', d: 'lemon', a: 'orange'} // * returns 1: true // * example 2: ini_set('phpjs.strictForIn', true); // * example 2: data = {d: 'lemon', a: 'orange', b: 'banana', c: 'apple'}; // * example 2: asort(data); // * results 2: data == {c: 'apple', b: 'banana', d: 'lemon', a: 'orange'} // * returns 2: true var valArr=[], keyArr=[], k, i, ret, sorter, that = this, strictForIn = false, populateArr = {}; switch (sort_flags) { case 'SORT_STRING': // compare items as strings sorter = function (a, b) { return that.strnatcmp(a, b); }; break; case 'SORT_LOCALE_STRING': // compare items as strings, based on the current locale (set with i18n_loc_set_default() as of PHP6) var loc = this.i18n_loc_get_default(); sorter = this.php_js.i18nLocales[loc].sorting; break; case 'SORT_NUMERIC': // compare items numerically sorter = function (a, b) { return (a - b); }; break; case 'SORT_REGULAR': // compare items normally (don't change types) default: sorter = function (a, b) { if (a > b) { return 1; } if (a < b) { return -1; } return 0; }; break; } var bubbleSort = function (keyArr, inputArr) { var i, j, tempValue, tempKeyVal; for (i = inputArr.length-2; i >= 0; i--) { for (j = 0; j <= i; j++) { ret = sorter(inputArr[j+1], inputArr[j]); if (ret < 0) { tempValue = inputArr[j]; inputArr[j] = inputArr[j+1]; inputArr[j+1] = tempValue; tempKeyVal = keyArr[j]; keyArr[j] = keyArr[j+1]; keyArr[j+1] = tempKeyVal; } } } }; // BEGIN REDUNDANT this.php_js = this.php_js || {}; this.php_js.ini = this.php_js.ini || {}; // END REDUNDANT strictForIn = this.php_js.ini['phpjs.strictForIn'] && this.php_js.ini['phpjs.strictForIn'].local_value && this.php_js.ini['phpjs.strictForIn'].local_value !== 'off'; populateArr = strictForIn ? inputArr : populateArr; // Get key and value arrays for (k in inputArr) { if (inputArr.hasOwnProperty(k)) { valArr.push(inputArr[k]); keyArr.push(k); if (strictForIn) { delete inputArr[k]; } } } try { // Sort our new temporary arrays bubbleSort(keyArr, valArr); } catch (e) { return false; } // Repopulate the old array for (i = 0; i < valArr.length; i++) { populateArr[keyArr[i]] = valArr[i]; } return strictForIn || populateArr;} |
Examples
» Example 1
Running
1 2 | data = {d: 'lemon', a: 'orange', b: 'banana', c: 'apple'}; data = asort(data); |
Should result in
1 | data == {c: 'apple', b: 'banana', d: 'lemon', a: 'orange'} |
» Example 2
Running
1 2 3 | ini_set('phpjs.strictForIn', true); data = {d: 'lemon', a: 'orange', b: 'banana', c: 'apple'}; asort(data); |
Should result in
1 | data == {c: 'apple', b: 'banana', d: 'lemon', a: 'orange'} |
Dependencies
In order to use this function, you also need:
Open syntax issues
php.js uses JsLint to help us keep our code consistent and prevent some common bugs.
Eventually we want all code to pass or at least take into consideration most fixes suggested by JsLint, following this JsLint configuration we’ve decided on.
Authors
Thanks to the following developers, you get to have asort goodness in JavaScript.
@Adam Wallner: Argh...Yes, you are right, and that was what I originally meant to do...Very glad you found that since it affected a good number of functions (though thankfully, fewer people probably using that option--still...). Now fixed in Git... Thank you...
It doesn't work in Firefox 3.6 (I haven't tested in other browsers, I need it only in firefox). The problem is in js you don't have associative arrays only objects.
Workaround: change the
populateArr = []
to
populateArr = {}
in the first line.
@Paulo Kuong: I have now fixed the function (and all others like it except for array_multisort which still needs to be fixed and array_unique which hasn't implemented its sorting argument at all yet) to return a (shallow) copy of the array unless the user does "ini_set('phpjs.strictForIn', true);" in which case it will attempt to work by reference (assumes an exclusively non-IE environment!).
That echo() was supposed to have a br line break in it but the form stripped the element out (seems the colorer is using strip_tags() instead of htmlentities())...
@paulo kuong: Darn, you're right! You can see how the array forms by adding our var_dump (with echo() dependency) after line 82 :
var_dump(inputArr);echo('<br />');
IE does preserve the right order as it goes through the for loop, but it seems to remember its previous order (since I see no other good explanation why it puts it back in exactly that non-alphabetical/non-reverse-alphabetical order)--no matter whether I delete (as we do now), set to undefined or some value and then delete, etc.
Nevertheless, everyone from Chrome, Opera, Safari, to Firefox handle this consistently.
Has anyone heard of this issue in IE before and any ways to get around it?
Glad you liked it, Jason.
That reminds me, I should give some credit for this function (and for arsort() too) to http://javascriptsource.com (specifically http://javascript.internet.com/math-related/bubble-sort.html ). They stated "the script is yours" (and my version is reasonably altered anyways), but they deserve some credit.
Kevin, a small thing, but if you were attending to these kinds of things, I should have put a semicolon after "var bubbleSort .... {...}" (or used regular function notation).


Brett Zamir
May 3rd