View: array_multisort

Function:
Description: Sort multiple arrays at once similar to how ORDER BY clause works in SQL.
Code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
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
    // *     results 2: characters == {D: 'Terra', C: 'Sabin', B: 'Locke', E: 'Edward', A: 'Edward'};
    // *     results 2: jobs == {D: 'Mage', C: 'Monk', B: 'Thief', E: 'Knight', A: 'Warrior'};
    // *     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
    // *     results 3: firstnames == ['John', 'John', 'John',   'John', 'James', 'James',  'James'];
    // *     results 3: lastnames ==  ['Adams','Adams','Kennedy','Tyler','Carter','Madison','Monroe'];
    // *     results 3: president ==  [2,      6,      35,       10,     39,       4,       5];
    // 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;
}
Comment on array_multisort version 25
Tests
Benchmark
[top]

Comments

There are no comments yet, be the first!

Please Login or Register to post comments.