从这个最初的问题,我将如何在多个字段应用排序?

使用这种稍作调整的结构,我将如何排序城市(上升)和价格(下降)?

var homes = [
    {"h_id":"3",
     "city":"Dallas",
     "state":"TX",
     "zip":"75201",
     "price":"162500"},
    {"h_id":"4",
     "city":"Bevery Hills",
     "state":"CA",
     "zip":"90210",
     "price":"319250"},
    {"h_id":"6",
     "city":"Dallas",
     "state":"TX",
     "zip":"75000",
     "price":"556699"},
    {"h_id":"5",
     "city":"New York",
     "state":"NY",
     "zip":"00010",
     "price":"962500"}
    ];

我喜欢的事实是,给出的答案提供了一个一般的方法。在我计划使用这段代码的地方,我将不得不对日期以及其他东西进行排序。“启动”对象的能力似乎很方便,如果不是有点麻烦的话。

我试图把这个答案构建成一个很好的通用示例,但我运气不太好。


当前回答

我一直在寻找类似的东西,最后得到了这个:

首先,我们有一个或多个排序函数,总是返回0、1或-1:

const sortByTitle = (a, b): number => 
  a.title === b.title ? 0 : a.title > b.title ? 1 : -1;

您可以为想要排序的其他属性创建更多函数。

然后我有一个函数将这些排序函数合并为一个:

const createSorter = (...sorters) => (a, b) =>
  sorters.reduce(
    (d, fn) => (d === 0 ? fn(a, b) : d),
    0
  );

这可以用来以一种可读的方式组合上述排序函数:

const sorter = createSorter(sortByTitle, sortByYear)

items.sort(sorter)

当一个排序函数返回0时,将调用下一个排序函数进行进一步排序。

其他回答

homes.sort(function(a,b) { return a.city - b.city } );
homes.sort(function(a,b){
    if (a.city==b.city){
        return parseFloat(b.price) - parseFloat(a.price);
    } else {
        return 0;
    }
});

下面的函数将允许您对一个或多个属性上的对象数组进行排序,对每个属性进行升序(默认值)或降序排序,并允许您选择是否执行区分大小写的比较。默认情况下,该函数执行不区分大小写的排序。

第一个参数必须是包含对象的数组。 后面的参数必须是一个以逗号分隔的字符串列表,这些字符串引用要排序的不同对象属性。最后一个参数(可选)是一个布尔值,用于选择是否执行区分大小写的排序——区分大小写的排序使用true。

默认情况下,该函数将按升序对每个属性/键排序。如果你想要一个特定的键按降序排序,那么取而代之的是传递一个这样格式的数组:['property_name', true]。

下面是该函数的一些示例用法,后面附有解释(其中homes是一个包含对象的数组):

objSort(homes, 'city')—>按城市排序(升序,不区分大小写)

objSort(homes, ['city', true])——>按城市排序(降序,不区分大小写)

objSort(homes, 'city', true)—>按城市然后价格排序(升序,区分大小写)

objSort(homes, 'city', 'price')——>先按城市再按价格排序(均为升序,不区分大小写)

objSort(homes, 'city', ['price', true])——>排序城市(升序)然后价格(降序),不区分大小写)

话不多说,下面是函数:

function objSort() {
    var args = arguments,
        array = args[0],
        case_sensitive, keys_length, key, desc, a, b, i;

    if (typeof arguments[arguments.length - 1] === 'boolean') {
        case_sensitive = arguments[arguments.length - 1];
        keys_length = arguments.length - 1;
    } else {
        case_sensitive = false;
        keys_length = arguments.length;
    }

    return array.sort(function (obj1, obj2) {
        for (i = 1; i < keys_length; i++) {
            key = args[i];
            if (typeof key !== 'string') {
                desc = key[1];
                key = key[0];
                a = obj1[args[i][0]];
                b = obj2[args[i][0]];
            } else {
                desc = false;
                a = obj1[args[i]];
                b = obj2[args[i]];
            }

            if (case_sensitive === false && typeof a === 'string') {
                a = a.toLowerCase();
                b = b.toLowerCase();
            }

            if (! desc) {
                if (a < b) return -1;
                if (a > b) return 1;
            } else {
                if (a > b) return -1;
                if (a < b) return 1;
            }
        }
        return 0;
    });
} //end of objSort() function

下面是一些样本数据:

var homes = [{
    "h_id": "3",
    "city": "Dallas",
    "state": "TX",
    "zip": "75201",
    "price": 162500
}, {
    "h_id": "4",
    "city": "Bevery Hills",
    "state": "CA",
    "zip": "90210",
    "price": 1000000
}, {
    "h_id": "5",
    "city": "new york",
    "state": "NY",
    "zip": "00010",
    "price": 1000000
}, {
    "h_id": "6",
    "city": "Dallas",
    "state": "TX",
    "zip": "85000",
    "price": 300000
}, {
    "h_id": "7",
    "city": "New York",
    "state": "NY",
    "zip": "00020",
    "price": 345000
}];

我一直在寻找类似的东西,最后得到了这个:

首先,我们有一个或多个排序函数,总是返回0、1或-1:

const sortByTitle = (a, b): number => 
  a.title === b.title ? 0 : a.title > b.title ? 1 : -1;

您可以为想要排序的其他属性创建更多函数。

然后我有一个函数将这些排序函数合并为一个:

const createSorter = (...sorters) => (a, b) =>
  sorters.reduce(
    (d, fn) => (d === 0 ? fn(a, b) : d),
    0
  );

这可以用来以一种可读的方式组合上述排序函数:

const sorter = createSorter(sortByTitle, sortByYear)

items.sort(sorter)

当一个排序函数返回0时,将调用下一个排序函数进行进一步排序。

一种多维排序方法,基于这个答案:

更新:这是一个“优化”版本。它做了更多的预处理,并预先为每个排序选项创建了一个比较函数。它可能需要更多的内存(因为它为每个排序选项存储了一个函数,但它应该更好一点,因为它不必在比较期间确定正确的设置。不过我没有做过任何侧写。

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;
        }
    }
}());

使用示例:

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

DEMO


最初的功能:

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 (a<b) result = reverse * -1;
           if (a>b) result = reverse * 1;
           if(result !== 0) break;
       }
       return result;
   }
};

DEMO

只需遵循排序标准列表

即使要封装36个排序标准,这段代码也将始终保持可读和可理解

Nina在这里提出的解决方案当然非常优雅,但它意味着要知道在布尔逻辑中,值为0对应的值为false,并且布尔测试在JavaScript中可以返回除true / false以外的值(这里是数值),这对于初学者来说总是令人困惑。

还要考虑谁需要维护您的代码。也许会是你:想象一下你自己花了几天的时间在另一个人的代码上,然后有了一个有害的错误……你读了几千行充满技巧的文章,都累坏了

const homes = [ { h_id: '3', city: 'Dallas', state: 'TX', zip: '75201', price: '162500' } , { h_id: '4', city: 'Bevery Hills', state: 'CA', zip: '90210', price: '319250' } , { h_id: '6', city: 'Dallas', state: 'TX', zip: '75000', price: '556699' } , { h_id: '5', city: 'New York', state: 'NY', zip: '00010', price: '962500' } ] const fSort = (a,b) => { let Dx = a.city.localeCompare(b.city) // 1st criteria if (Dx===0) Dx = Number(b.price) - Number(a.price) // 2nd // if (Dx===0) Dx = ... // 3rd // if (Dx===0) Dx = ... // 4th.... return Dx } console.log( homes.sort(fSort))