/_octopress/source/functions/array_multisort/index.markdown
Markdown | 317 lines | 286 code | 31 blank | 0 comment | 0 complexity | bdb1c350f885bea882e9b3e8053ecb4b MD5 | raw file
- ---
- layout: page
- title: "JavaScript array_multisort function"
- comments: true
- sharing: true
- footer: true
- alias:
- - /functions/view/array_multisort:830
- - /functions/view/array_multisort
- - /functions/view/830
- - /functions/array_multisort:830
- - /functions/830
- ---
- <!-- Generated by Rakefile:build -->
- A JavaScript equivalent of PHP's array_multisort
- {% codeblock array/array_multisort.js lang:js https://raw.github.com/kvz/phpjs/master/functions/array/array_multisort.js raw on github %}
- function array_multisort(arr) {
- // discuss at: http://phpjs.org/functions/array_multisort/
- // original by: Theriault
- // example 1: array_multisort([1, 2, 1, 2, 1, 2], [1, 2, 3, 4, 5, 6]);
- // returns 1: true
- // example 2: characters = {A: 'Edward', B: 'Locke', C: 'Sabin', D: 'Terra', E: 'Edward'};
- // example 2: jobs = {A: 'Warrior', B: 'Thief', C: 'Monk', D: 'Mage', E: 'Knight'};
- // example 2: array_multisort(characters, 'SORT_DESC', 'SORT_STRING', jobs, 'SORT_ASC', 'SORT_STRING');
- // returns 2: true
- // example 3: lastnames = [ 'Carter','Adams','Monroe','Tyler','Madison','Kennedy','Adams'];
- // example 3: firstnames = ['James', 'John' ,'James', 'John', 'James', 'John', 'John'];
- // example 3: president = [ 39, 6, 5, 10, 4, 35, 2 ];
- // example 3: array_multisort(firstnames, 'SORT_DESC', 'SORT_STRING', lastnames, 'SORT_ASC', 'SORT_STRING', president, 'SORT_NUMERIC');
- // returns 3: true
- // flags: Translation table for sort arguments. Each argument turns on certain bits in the flag byte through addition.
- // bits: HGFE DCBA
- // args: Holds pointer to arguments for reassignment
- var g, i, j, k, l, sal, vkey, elIndex, lastSorts, tmpArray, zlast;
- var sortFlag = [0];
- var thingsToSort = [];
- var nLastSort = [];
- var lastSort = [];
- var args = arguments; // possibly redundant
- var flags = {
- 'SORT_REGULAR': 16,
- 'SORT_NUMERIC': 17,
- 'SORT_STRING': 18,
- 'SORT_ASC': 32,
- 'SORT_DESC': 40
- };
- var sortDuplicator = function(a, b) {
- return nLastSort.shift();
- };
- var sortFunctions = [
- [
- function(a, b) {
- lastSort.push(a > b ? 1 : (a < b ? -1 : 0));
- return a > b ? 1 : (a < b ? -1 : 0);
- },
- function(a, b) {
- lastSort.push(b > a ? 1 : (b < a ? -1 : 0));
- return b > a ? 1 : (b < a ? -1 : 0);
- }
- ],
- [
- function(a, b) {
- lastSort.push(a - b);
- return a - b;
- },
- function(a, b) {
- lastSort.push(b - a);
- return b - a;
- }
- ],
- [
- function(a, b) {
- lastSort.push((a + '') > (b + '') ? 1 : ((a + '') < (b + '') ? -1 : 0));
- return (a + '') > (b + '') ? 1 : ((a + '') < (b + '') ? -1 : 0);
- },
- function(a, b) {
- lastSort.push((b + '') > (a + '') ? 1 : ((b + '') < (a + '') ? -1 : 0));
- return (b + '') > (a + '') ? 1 : ((b + '') < (a + '') ? -1 : 0);
- }
- ]
- ];
- var sortArrs = [
- []
- ];
- var sortKeys = [
- []
- ];
- // Store first argument into sortArrs and sortKeys if an Object.
- // First Argument should be either a Javascript Array or an Object, otherwise function would return FALSE like in PHP
- if (Object.prototype.toString.call(arr) === '[object Array]') {
- sortArrs[0] = arr;
- } else if (arr && typeof arr === 'object') {
- for (i in arr) {
- if (arr.hasOwnProperty(i)) {
- sortKeys[0].push(i);
- sortArrs[0].push(arr[i]);
- }
- }
- } else {
- return false;
- }
- // arrMainLength: Holds the length of the first array. All other arrays must be of equal length, otherwise function would return FALSE like in PHP
- //
- // sortComponents: Holds 2 indexes per every section of the array that can be sorted. As this is the start, the whole array can be sorted.
- var arrMainLength = sortArrs[0].length;
- var sortComponents = [0, arrMainLength];
- // Loop through all other arguments, checking lengths and sort flags of arrays and adding them to the above variables.
- var argl = arguments.length;
- for (j = 1; j < argl; j++) {
- if (Object.prototype.toString.call(arguments[j]) === '[object Array]') {
- sortArrs[j] = arguments[j];
- sortFlag[j] = 0;
- if (arguments[j].length !== arrMainLength) {
- return false;
- }
- } else if (arguments[j] && typeof arguments[j] === 'object') {
- sortKeys[j] = [];
- sortArrs[j] = [];
- sortFlag[j] = 0;
- for (i in arguments[j]) {
- if (arguments[j].hasOwnProperty(i)) {
- sortKeys[j].push(i);
- sortArrs[j].push(arguments[j][i]);
- }
- }
- if (sortArrs[j].length !== arrMainLength) {
- return false;
- }
- } else if (typeof arguments[j] === 'string') {
- var lFlag = sortFlag.pop();
- // Keep extra parentheses around latter flags check to avoid minimization leading to CDATA closer
- if (typeof flags[arguments[j]] === 'undefined' || ((((flags[arguments[j]]) >>> 4) & (lFlag >>> 4)) > 0)) {
- return false;
- }
- sortFlag.push(lFlag + flags[arguments[j]]);
- } else {
- return false;
- }
- }
- for (i = 0; i !== arrMainLength; i++) {
- thingsToSort.push(true);
- }
- // Sort all the arrays....
- for (i in sortArrs) {
- if (sortArrs.hasOwnProperty(i)) {
- lastSorts = [];
- tmpArray = [];
- elIndex = 0;
- nLastSort = [];
- lastSort = [];
- // If there are no sortComponents, then no more sorting is neeeded. Copy the array back to the argument.
- if (sortComponents.length === 0) {
- if (Object.prototype.toString.call(arguments[i]) === '[object Array]') {
- args[i] = sortArrs[i];
- } else {
- for (k in arguments[i]) {
- if (arguments[i].hasOwnProperty(k)) {
- delete arguments[i][k];
- }
- }
- sal = sortArrs[i].length;
- for (j = 0, vkey = 0; j < sal; j++) {
- vkey = sortKeys[i][j];
- args[i][vkey] = sortArrs[i][j];
- }
- }
- delete sortArrs[i];
- delete sortKeys[i];
- continue;
- }
- // Sort function for sorting. Either sorts asc or desc, regular/string or numeric.
- var sFunction = sortFunctions[(sortFlag[i] & 3)][((sortFlag[i] & 8) > 0) ? 1 : 0];
- // Sort current array.
- for (l = 0; l !== sortComponents.length; l += 2) {
- tmpArray = sortArrs[i].slice(sortComponents[l], sortComponents[l + 1] + 1);
- tmpArray.sort(sFunction);
- lastSorts[l] = [].concat(lastSort); // Is there a better way to copy an array in Javascript?
- elIndex = sortComponents[l];
- for (g in tmpArray) {
- if (tmpArray.hasOwnProperty(g)) {
- sortArrs[i][elIndex] = tmpArray[g];
- elIndex++;
- }
- }
- }
- // Duplicate the sorting of the current array on future arrays.
- sFunction = sortDuplicator;
- for (j in sortArrs) {
- if (sortArrs.hasOwnProperty(j)) {
- if (sortArrs[j] === sortArrs[i]) {
- continue;
- }
- for (l = 0; l !== sortComponents.length; l += 2) {
- tmpArray = sortArrs[j].slice(sortComponents[l], sortComponents[l + 1] + 1);
- nLastSort = [].concat(lastSorts[l]); // alert(l + ':' + nLastSort);
- tmpArray.sort(sFunction);
- elIndex = sortComponents[l];
- for (g in tmpArray) {
- if (tmpArray.hasOwnProperty(g)) {
- sortArrs[j][elIndex] = tmpArray[g];
- elIndex++;
- }
- }
- }
- }
- }
- // Duplicate the sorting of the current array on array keys
- for (j in sortKeys) {
- if (sortKeys.hasOwnProperty(j)) {
- for (l = 0; l !== sortComponents.length; l += 2) {
- tmpArray = sortKeys[j].slice(sortComponents[l], sortComponents[l + 1] + 1);
- nLastSort = [].concat(lastSorts[l]);
- tmpArray.sort(sFunction);
- elIndex = sortComponents[l];
- for (g in tmpArray) {
- if (tmpArray.hasOwnProperty(g)) {
- sortKeys[j][elIndex] = tmpArray[g];
- elIndex++;
- }
- }
- }
- }
- }
- // Generate the next sortComponents
- zlast = null;
- sortComponents = [];
- for (j in sortArrs[i]) {
- if (sortArrs[i].hasOwnProperty(j)) {
- if (!thingsToSort[j]) {
- if ((sortComponents.length & 1)) {
- sortComponents.push(j - 1);
- }
- zlast = null;
- continue;
- }
- if (!(sortComponents.length & 1)) {
- if (zlast !== null) {
- if (sortArrs[i][j] === zlast) {
- sortComponents.push(j - 1);
- } else {
- thingsToSort[j] = false;
- }
- }
- zlast = sortArrs[i][j];
- } else {
- if (sortArrs[i][j] !== zlast) {
- sortComponents.push(j - 1);
- zlast = sortArrs[i][j];
- }
- }
- }
- }
- if (sortComponents.length & 1) {
- sortComponents.push(j);
- }
- if (Object.prototype.toString.call(arguments[i]) === '[object Array]') {
- args[i] = sortArrs[i];
- } else {
- for (j in arguments[i]) {
- if (arguments[i].hasOwnProperty(j)) {
- delete arguments[i][j];
- }
- }
- sal = sortArrs[i].length;
- for (j = 0, vkey = 0; j < sal; j++) {
- vkey = sortKeys[i][j];
- args[i][vkey] = sortArrs[i][j];
- }
- }
- delete sortArrs[i];
- delete sortKeys[i];
- }
- }
- return true;
- }
- {% endcodeblock %}
- - [Raw function on GitHub](https://github.com/kvz/phpjs/blob/master/functions/array/array_multisort.js)
- Please note that php.js uses JavaScript objects as substitutes for PHP arrays, they are
- the closest match to this hashtable-like data structure.
- Please also note that php.js offers community built functions and goes by the
- [McDonald's Theory](https://medium.com/what-i-learned-building/9216e1c9da7d). We'll put online
- functions that are far from perfect, in the hopes to spark better contributions.
- Do you have one? Then please just:
- - [Edit on GitHub](https://github.com/kvz/phpjs/edit/master/functions/array/array_multisort.js)
- ### Other PHP functions in the array extension
- {% render_partial _includes/custom/array.html %}