How to sort an array of objects by multiple fields?

后端 未结 30 2331
北恋
北恋 2020-11-21 11:34

From this original question, how would I apply a sort on multiple fields?

Using this slightly adapted structure, how would I sort city (ascending) & then price (

30条回答
  •  粉色の甜心
    2020-11-21 12:29

    A multi dimensional sorting method, based on this answer:

    Update: Here is an "optimized" version. It does a lot more preprocessing and creates a comparison function for each sorting option beforehand. It might need more more memory (as it stores a function for each sorting option, but it should preform a bit better as it does not have to determine the correct settings during the comparison. I have not done any profiling though.

    var sort_by;
    
    (function() {
        // utility functions
        var default_cmp = function(a, b) {
                if (a == b) return 0;
                return a < b ? -1 : 1;
            },
            getCmpFunc = function(primer, reverse) {
                var dfc = default_cmp, // closer in scope
                    cmp = default_cmp;
                if (primer) {
                    cmp = function(a, b) {
                        return dfc(primer(a), primer(b));
                    };
                }
                if (reverse) {
                    return function(a, b) {
                        return -1 * cmp(a, b);
                    };
                }
                return cmp;
            };
    
        // actual implementation
        sort_by = function() {
            var fields = [],
                n_fields = arguments.length,
                field, name, reverse, cmp;
    
            // preprocess sorting options
            for (var i = 0; i < n_fields; i++) {
                field = arguments[i];
                if (typeof field === 'string') {
                    name = field;
                    cmp = default_cmp;
                }
                else {
                    name = field.name;
                    cmp = getCmpFunc(field.primer, field.reverse);
                }
                fields.push({
                    name: name,
                    cmp: cmp
                });
            }
    
            // final comparison function
            return function(A, B) {
                var a, b, name, result;
                for (var i = 0; i < n_fields; i++) {
                    result = 0;
                    field = fields[i];
                    name = field.name;
    
                    result = field.cmp(A[name], B[name]);
                    if (result !== 0) break;
                }
                return result;
            }
        }
    }());
    

    Example usage:

    homes.sort(sort_by('city', {name:'price', primer: parseInt, reverse: true}));
    

    DEMO


    Original function:

    var sort_by = function() {
       var fields = [].slice.call(arguments),
           n_fields = fields.length;
    
       return function(A,B) {
           var a, b, field, key, primer, reverse, result, i;
    
           for(i = 0; i < n_fields; i++) {
               result = 0;
               field = fields[i];
    
               key = typeof field === 'string' ? field : field.name;
    
               a = A[key];
               b = B[key];
    
               if (typeof field.primer  !== 'undefined'){
                   a = field.primer(a);
                   b = field.primer(b);
               }
    
               reverse = (field.reverse) ? -1 : 1;
    
               if (ab) result = reverse * 1;
               if(result !== 0) break;
           }
           return result;
       }
    };
    

    DEMO

提交回复
热议问题