UNPKG

phpjs

Version:

php.js offers community built php functions in javascript

316 lines (298 loc) 11.1 kB
function array_multisort(arr) { // + 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 // Fix: this function must be fixed like asort(), etc., to return a (shallow) copy by default, since IE does not support! // VARIABLE DESCRIPTIONS // // flags: Translation table for sort arguments. Each argument turns on certain bits in the flag byte through addition. // bits: HGFE DCBA // bit A: Only turned on if SORT_NUMERIC was an argument. // bit B: Only turned on if SORT_STRING was an argument. // bit C: Reserved bit for SORT_ASC; not turned on. // bit D: Only turned on if SORT_DESC was an argument. // bit E: Turned on if either SORT_REGULAR, SORT_NUMERIC, or SORT_STRING was an argument. If already turned on, function would return FALSE like in PHP. // bit F: Turned on if either SORT_ASC or SORT_DESC was an argument. If already turned on, function would return FALSE like in PHP. // bit G and H: (Unused) // // sortFlag: Holds sort flag byte of every array argument. // // sortArrs: Holds the values of array arguments. // // sortKeys: Holds the keys of object arguments. // // nLastSort: Holds a copy of the current lastSort so that the lastSort is not destroyed // // nLastSort: Holds a copy of the current lastSort so that the lastSort is not destroyed // // args: Holds pointer to arguments for reassignment // // lastSort: Holds the last Javascript sort pattern to duplicate the sort for the last sortComponent. // // lastSorts: Holds the lastSort for each sortComponent to duplicate the sort of each component on each array. // // tmpArray: Holds a copy of the last sortComponent's array elements to reiterate over the array // // elIndex: Holds the index of the last sortComponent's array elements to reiterate over the array // // sortDuplicator: Function for duplicating previous sort. // // sortRegularASC: Function for sorting regular, ascending. // // sortRegularDESC: Function for sorting regular, descending. // // thingsToSort: Holds a bit that indicates which indexes in the arrays can be sorted. Updated after every array is sorted. var argl = arguments.length, sal = 0, flags = { 'SORT_REGULAR': 16, 'SORT_NUMERIC': 17, 'SORT_STRING': 18, 'SORT_ASC': 32, 'SORT_DESC': 40 }, sortArrs = [ [] ], sortFlag = [0], sortKeys = [ [] ], g = 0, i = 0, j = 0, k = '', l = 0, thingsToSort = [], vkey = 0, zlast = null, args = arguments, nLastSort = [], lastSort = [], lastSorts = [], tmpArray = [], elIndex = 0, sortDuplicator = function(a, b) { return nLastSort.shift(); }; 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); }] ]; // 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, sortComponents = [0, arrMainLength]; // Loop through all other arguments, checking lengths and sort flags of arrays and adding them to the above variables. 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(); if (typeof flags[arguments[j]] === 'undefined' || ((((flags[arguments[j]]) >>> 4) & (lFlag >>> 4)) > 0)) { // Keep extra parentheses around latter flags check to avoid minimization leading to CDATA closer 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 ther 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; }