简体   繁体   English

如何按多个字段对对象数组进行排序?

[英]How to sort an array of objects by multiple fields?

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 (descending)?使用这种稍微调整过的结构,我将如何对城市(升序)和价格(降序)进行排序?

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"}
    ];

I liked the fact than an answer was given which provided a general approach.我喜欢这个事实,而不是给出了提供一般方法的答案 Where I plan to use this code, I will have to sort dates as well as other things.在我计划使用此代码的地方,我将不得不对日期和其他内容进行排序。 The ability to "prime" the object seemed handy, if not a little cumbersome. “启动”object 的能力似乎很方便,即使不是有点麻烦。

I've tried to build this answer into a nice generic example, but I'm not having much luck.我试图将这个答案构建成一个很好的通用示例,但我运气不佳。

You could use a chained sorting approach by taking the delta of values until it reaches a value not equal to zero.您可以使用链式排序方法,获取值的增量,直到它达到不等于零的值。

 var data = [{ 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" }]; data.sort(function (a, b) { return a.city.localeCompare(b.city) || b.price - a.price; }); console.log(data);
 .as-console-wrapper { max-height: 100% !important; top: 0; }

Or, using es6, simply:或者,使用 es6,简单地:

data.sort((a, b) => a.city.localeCompare(b.city) || b.price - a.price);

for a non-generic, simple solution to your exact problem:对于您的确切问题的非通用,简单的解决方案:

homes.sort(
   function(a, b) {          
      if (a.city === b.city) {
         // Price is only important when cities are the same
         return b.price - a.price;
      }
      return a.city > b.city ? 1 : -1;
   });

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

DEMO演示

Here is a simple functional generic approach.这是一个简单的功能通用方法。 Specify sort order using array.使用数组指定排序顺序。 Prepend minus to specify descending order.在前面加上减号以指定降序。

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"}
    ];

homes.sort(fieldSorter(['city', '-price']));
// homes.sort(fieldSorter(['zip', '-state', 'price'])); // alternative

function fieldSorter(fields) {
    return function (a, b) {
        return fields
            .map(function (o) {
                var dir = 1;
                if (o[0] === '-') {
                   dir = -1;
                   o=o.substring(1);
                }
                if (a[o] > b[o]) return dir;
                if (a[o] < b[o]) return -(dir);
                return 0;
            })
            .reduce(function firstNonZeroValue (p,n) {
                return p ? p : n;
            }, 0);
    };
}

Edit: in ES6 it's even shorter!编辑:在 ES6 中它甚至更短!

 "use strict"; const fieldSorter = (fields) => (a, b) => fields.map(o => { let dir = 1; if (o[0] === '-') { dir = -1; o=o.substring(1); } return a[o] > b[o] ? dir : a[o] < b[o] ? -(dir) : 0; }).reduce((p, n) => p ? p : n, 0); 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 sortedHomes = homes.sort(fieldSorter(['state', '-price'])); document.write('<pre>' + JSON.stringify(sortedHomes, null, '\t') + '</pre>')

I made a quite generic multi feature sorter today.我今天做了一个非常通用的多特征分类器。 You can have a look at thenBy.js here: https://github.com/Teun/thenBy.js您可以在这里查看 thenBy.js: https ://github.com/Teun/thenBy.js

It allows you to use the standard Array.sort, but with firstBy().thenBy().thenBy() style.它允许您使用标准的 Array.sort,但使用 firstBy().thenBy().thenBy() 样式。 It is way less code and complexity than the solutions posted above.与上面发布的解决方案相比,它的代码和复杂性要少得多。

Here's an extensible way to sort by multiple fields.这是一种按多个字段排序的可扩展方式。

homes.sort(function(left, right) {
    var city_order = left.city.localeCompare(right.city);
    var price_order = parseInt(left.price) - parseInt(right.price);
    return city_order || -price_order;
});

Notes笔记

  • A function passed to array sort is expected to return negative, zero, positive to indicate less, equal, greater.传递给数组排序的函数应返回负数、零、正数以表示小于、等于、大于。
  • a.localeCompare(b) is universally supported for strings, and returns -1,0,1 if a<b , a==b , a>b . a.localeCompare(b)普遍支持字符串,如果a<b , a==b , a>b则返回 -1,0,1 。
  • Subtraction works on numeric fields, because a - b gives -,0,+ if a<b , a==b , a>b .减法适用于数字字段,因为如果a<ba==ba>ba - b给出 -,0,+ 。
  • || in the last line gives city priority over price .在最后一行中, city优先于price
  • Negate to reverse order in any field, as in -price_order否定以反转任何字段中的顺序,如-price_order
  • Add new fields to the or-chain: return city_order || -price_order || date_order;向 or 链添加新字段: return city_order || -price_order || date_order; return city_order || -price_order || date_order;
  • Date compare with subtraction, because date math converts to milliseconds since 1970.日期与减法比较,因为自 1970 年以来日期数学转换为毫秒。
    var date_order = new Date(left.date) - new Date(right.date);
  • Boolean compare with subtraction, which is guaranteed to turn true and false to 1 and 0 (therefore the subtraction produces -1 or 0 or 1).布尔值与减法比较, 保证将真假转为 1 和 0(因此减法产生 -1 或 0 或 1)。
    var goodness_order = Boolean(left.is_good) - Boolean(right.is_good)
    This is unusual enough that I'd suggest drawing attention with the Boolean constructor, even if they're already boolean.这很不寻常,我建议使用布尔构造函数引起注意,即使它们已经是布尔值。

This is a complete cheat but I think that it adds value to this question because it's basically a canned library function that you can use out-of-the box.这是一个完整的作弊,但我认为它为这个问题增加了价值,因为它基本上是一个罐头库函数,您可以开箱即用地使用。

If your code has access to lodash or a lodash compatible library like underscore then you can use the _.sortBy method.如果您的代码可以访问lodashunderscore之类的 lodash 兼容库,那么您可以使用_.sortBy方法。 The snippet below is copied directly from the lodash documentation .下面的代码片段直接从lodash 文档中复制而来。

The commented results in the examples looks like they return arrays of arrays but that's just showing the order and not the actual results which are an array of objects.示例中的注释结果看起来像是返回数组数组,但这只是显示顺序,而不是对象数组的实际结果。

var users = [
  { 'user': 'fred',   'age': 48 },
  { 'user': 'barney', 'age': 36 },
  { 'user': 'fred',   'age': 40 },
  { 'user': 'barney', 'age': 34 }
];

_.sortBy(users, [function(o) { return o.user; }]);
 // => objects for [['barney', 36], ['barney', 34], ['fred', 48], ['fred', 40]]

_.sortBy(users, ['user', 'age']);
// => objects for [['barney', 34], ['barney', 36], ['fred', 40], ['fred', 48]]

The following function will allow you to sort an array of objects on one or multiple properties, either ascending (default) or descending on each property, and allow you to choose whether or not to perform case sensitive comparisons.以下函数将允许您对一个或多个属性的对象数组进行排序,对每个属性升序(默认)或降序,并允许您选择是否执行区分大小写的比较。 By default, this function performs case insensitive sorts.默认情况下,此函数执行不区分大小写的排序。

The first argument must be the array containing the objects.第一个参数必须是包含对象的数组。 The subsequent argument(s) must be a comma separated list of strings that reference the different object properties to sort by.随后的参数必须是一个逗号分隔的字符串列表,这些字符串引用不同的对象属性进行排序。 The last argument (which is optional) is a boolean to choose whether or not to perform case sensitive sorts - use true for case sensitive sorts.最后一个参数(可选)是一个布尔值,用于选择是否执行区分大小写的排序 - 对区分大小写的排序使用true

The function will sort each property/key in ascending order by default.默认情况下,该函数将按升序对每个属性/键进行排序。 If you want a particular key to sort in descending order, then instead pass in an array in this format: ['property_name', true] .如果您希望特定键按降序排序,则改为以以下格式传入数组: ['property_name', true]

Here are some sample uses of the function followed by an explanation (where homes is an array containing the objects):以下是该函数的一些示例用法,然后是说明(其中, homes是包含对象的数组):

objSort(homes, 'city') --> sort by city (ascending, case in-sensitive) objSort(homes, 'city') --> 按城市排序(升序,不区分大小写)

objSort(homes, ['city', true]) --> sort by city (descending, case in-sensitive) objSort(homes, ['city', true]) --> 按城市排序(降序,不区分大小写)

objSort(homes, 'city', true) --> sort by city then price (ascending, case sensitive ) objSort(homes, 'city', true) --> 按城市排序然后价格(升序,区分大小写

objSort(homes, 'city', 'price') --> sort by city then price (both ascending, case in-sensitive) objSort(homes, 'city', 'price') --> 按城市然后价格排序(均升序,不区分大小写)

objSort(homes, 'city', ['price', true]) --> sort by city (ascending) then price (descending), case in-sensitive) objSort(homes, 'city', ['price', true]) --> 按城市(升序)然后价格(降序)排序,不区分大小写)

And without further ado, here's the function:事不宜迟,功能如下:

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

And here's some sample data:这是一些示例数据:

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
}];

A dynamic way to do that with MULTIPLE keys:使用 MULTIPLE 键的动态方法:

  • filter unique values from each col/key of sort从排序的每个列/键中过滤唯一值
  • put in order or reverse it整理或颠倒它
  • add weights width zeropad for each object based on indexOf(value) keys values根据 indexOf(value) 键值为每个对象添加权重宽度 zeropad
  • sort using caclutated weights使用计算权重排序

在此处输入图像描述

Object.defineProperty(Array.prototype, 'orderBy', {
value: function(sorts) { 
    sorts.map(sort => {            
        sort.uniques = Array.from(
            new Set(this.map(obj => obj[sort.key]))
        );
        
        sort.uniques = sort.uniques.sort((a, b) => {
            if (typeof a == 'string') {
                return sort.inverse ? b.localeCompare(a) : a.localeCompare(b);
            }
            else if (typeof a == 'number') {
                return sort.inverse ? b - a : a - b;
            }
            else if (typeof a == 'boolean') {
                let x = sort.inverse ? (a === b) ? 0 : a? -1 : 1 : (a === b) ? 0 : a? 1 : -1;
                return x;
            }
            return 0;
        });
    });

    const weightOfObject = (obj) => {
        let weight = "";
        sorts.map(sort => {
            let zeropad = `${sort.uniques.length}`.length;
            weight += sort.uniques.indexOf(obj[sort.key]).toString().padStart(zeropad, '0');
        });
        //obj.weight = weight; // if you need to see weights
        return weight;
    }

    this.sort((a, b) => {
        return weightOfObject(a).localeCompare( weightOfObject(b) );
    });
    
    return this;
}
});

Use:利用:

// works with string, number and boolean
let sortered = your_array.orderBy([
    {key: "type", inverse: false}, 
    {key: "title", inverse: false},
    {key: "spot", inverse: false},
    {key: "internal", inverse: true}
]);

在此处输入图像描述

Here's a generic multidimensional sort, allowing for reversing and/or mapping on each level.这是一个通用的多维排序,允许在每个级别上进行反转和/或映射。

Written in Typescript.用打字稿写的。 For Javascript, check out this JSFiddle对于 Javascript,请查看此JSFiddle

The Code编码

type itemMap = (n: any) => any;

interface SortConfig<T> {
  key: keyof T;
  reverse?: boolean;
  map?: itemMap;
}

export function byObjectValues<T extends object>(keys: ((keyof T) | SortConfig<T>)[]): (a: T, b: T) => 0 | 1 | -1 {
  return function(a: T, b: T) {
    const firstKey: keyof T | SortConfig<T> = keys[0];
    const isSimple = typeof firstKey === 'string';
    const key: keyof T = isSimple ? (firstKey as keyof T) : (firstKey as SortConfig<T>).key;
    const reverse: boolean = isSimple ? false : !!(firstKey as SortConfig<T>).reverse;
    const map: itemMap | null = isSimple ? null : (firstKey as SortConfig<T>).map || null;

    const valA = map ? map(a[key]) : a[key];
    const valB = map ? map(b[key]) : b[key];
    if (valA === valB) {
      if (keys.length === 1) {
        return 0;
      }
      return byObjectValues<T>(keys.slice(1))(a, b);
    }
    if (reverse) {
      return valA > valB ? -1 : 1;
    }
    return valA > valB ? 1 : -1;
  };
}

Usage Examples使用示例

Sorting a people array by last name, then first name:按姓氏排序人员数组,然后是名字:

interface Person {
  firstName: string;
  lastName: string;
}

people.sort(byObjectValues<Person>(['lastName','firstName']));

Sort language codes by their name , not their language code (see map ), then by descending version (see reverse ).名称排序语言代码,而不是语言代码(参见map ),然后按版本降序(参见reverse )。

interface Language {
  code: string;
  version: number;
}

// languageCodeToName(code) is defined elsewhere in code

languageCodes.sort(byObjectValues<Language>([
  {
    key: 'code',
    map(code:string) => languageCodeToName(code),
  },
  {
    key: 'version',
    reverse: true,
  }
]));

Here's another one that's perhaps closer to your idea for the syntax这是另一个可能更接近您对语法的想法

function sortObjects(objArray, properties /*, primers*/) {
    var primers = arguments[2] || {}; // primers are optional

    properties = properties.map(function(prop) {
        if( !(prop instanceof Array) ) {
            prop = [prop, 'asc']
        }
        if( prop[1].toLowerCase() == 'desc' ) {
            prop[1] = -1;
        } else {
            prop[1] = 1;
        }
        return prop;
    });

    function valueCmp(x, y) {
        return x > y ? 1 : x < y ? -1 : 0; 
    }

    function arrayCmp(a, b) {
        var arr1 = [], arr2 = [];
        properties.forEach(function(prop) {
            var aValue = a[prop[0]],
                bValue = b[prop[0]];
            if( typeof primers[prop[0]] != 'undefined' ) {
                aValue = primers[prop[0]](aValue);
                bValue = primers[prop[0]](bValue);
            }
            arr1.push( prop[1] * valueCmp(aValue, bValue) );
            arr2.push( prop[1] * valueCmp(bValue, aValue) );
        });
        return arr1 < arr2 ? -1 : 1;
    }

    objArray.sort(function(a, b) {
        return arrayCmp(a, b);
    });
}

// just for fun use this to reverse the city name when sorting
function demoPrimer(str) {
    return str.split('').reverse().join('');
}

// Example
sortObjects(homes, ['city', ['price', 'desc']], {city: demoPrimer});

Demo: http://jsfiddle.net/Nq4dk/2/演示:http: //jsfiddle.net/Nq4dk/2/


Edit: Just for fun, here's a variation that just takes an sql-like string, so you can do sortObjects(homes, "city, price desc")编辑:只是为了好玩,这里有一个变体,它只需要一个类似 sql 的字符串,所以你可以做sortObjects(homes, "city, price desc")

function sortObjects(objArray, properties /*, primers*/) {
    var primers = arguments[2] || {};

    properties = properties.split(/\s*,\s*/).map(function(prop) {
        prop = prop.match(/^([^\s]+)(\s*desc)?/i);
        if( prop[2] && prop[2].toLowerCase() === 'desc' ) {
            return [prop[1] , -1];
        } else {
            return [prop[1] , 1];
        }
    });

    function valueCmp(x, y) {
        return x > y ? 1 : x < y ? -1 : 0; 
    }

    function arrayCmp(a, b) {
        var arr1 = [], arr2 = [];
        properties.forEach(function(prop) {
            var aValue = a[prop[0]],
                bValue = b[prop[0]];
            if( typeof primers[prop[0]] != 'undefined' ) {
                aValue = primers[prop[0]](aValue);
                bValue = primers[prop[0]](bValue);
            }
            arr1.push( prop[1] * valueCmp(aValue, bValue) );
            arr2.push( prop[1] * valueCmp(bValue, aValue) );
        });
        return arr1 < arr2 ? -1 : 1;
    }

    objArray.sort(function(a, b) {
        return arrayCmp(a, b);
    });
}

why complicate?为什么复杂? just sort it twice!只需排序两次! this works perfectly: (just make sure to reverse the importance order from least to most):这完美地工作:(只需确保将重要性顺序从最低到最高颠倒):

jj.sort( (a, b) => (a.id >= b.id) ? 1 : -1 );
jj.sort( (a, b) => (a.status >= b.status) ? 1 : -1 );

Simpler one:更简单的一个:

var someArray = [...];

function generateSortFn(props) {
    return function (a, b) {
        for (var i = 0; i < props.length; i++) {
            var prop = props[i];
            var name = prop.name;
            var reverse = prop.reverse;
            if (a[name] < b[name])
                return reverse ? 1 : -1;
            if (a[name] > b[name])
                return reverse ? -1 : 1;
        }
        return 0;
    };
};

someArray.sort(generateSortFn([{name: 'prop1', reverse: true}, {name: 'prop2'}]));

Here's my solution based on the Schwartzian transform idiom , hope you find it useful.这是我基于Schwartzian transform idiom的解决方案,希望对您有用。

function sortByAttribute(array, ...attrs) {
  // generate an array of predicate-objects contains
  // property getter, and descending indicator
  let predicates = attrs.map(pred => {
    let descending = pred.charAt(0) === '-' ? -1 : 1;
    pred = pred.replace(/^-/, '');
    return {
      getter: o => o[pred],
      descend: descending
    };
  });
  // schwartzian transform idiom implementation. aka: "decorate-sort-undecorate"
  return array.map(item => {
    return {
      src: item,
      compareValues: predicates.map(predicate => predicate.getter(item))
    };
  })
  .sort((o1, o2) => {
    let i = -1, result = 0;
    while (++i < predicates.length) {
      if (o1.compareValues[i] < o2.compareValues[i]) result = -1;
      if (o1.compareValues[i] > o2.compareValues[i]) result = 1;
      if (result *= predicates[i].descend) break;
    }
    return result;
  })
  .map(item => item.src);
}

Here's an example how to use it:这是一个如何使用它的示例:

let games = [
  { name: 'Pako',              rating: 4.21 },
  { name: 'Hill Climb Racing', rating: 3.88 },
  { name: 'Angry Birds Space', rating: 3.88 },
  { name: 'Badland',           rating: 4.33 }
];

// sort by one attribute
console.log(sortByAttribute(games, 'name'));
// sort by mupltiple attributes
console.log(sortByAttribute(games, '-rating', 'name'));

I like SnowBurnt's approach but it needs a tweak to test for equivalence on city NOT a difference.我喜欢 SnowBurnt 的方法,但它需要调整来测试城市的等效性,而不是差异。

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

Another way另一种方式

 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"} ]; function sortBy(ar) { return ar.sort((a, b) => a.city === b.city ? b.price.toString().localeCompare(a.price) : a.city.toString().localeCompare(b.city)); } console.log(sortBy(homes));

Just another option.只是另一种选择。 Consider to use the following utility function:考虑使用以下效用函数:

/** Performs comparing of two items by specified properties
 * @param  {Array} props for sorting ['name'], ['value', 'city'], ['-date']
 * to set descending order on object property just add '-' at the begining of property
 */
export const compareBy = (...props) => (a, b) => {
  for (let i = 0; i < props.length; i++) {
    const ascValue = props[i].startsWith('-') ? -1 : 1;
    const prop = props[i].startsWith('-') ? props[i].substr(1) : props[i];
    if (a[prop] !== b[prop]) {
      return a[prop] > b[prop] ? ascValue : -ascValue;
    }
  }
  return 0;
};

Example of usage (in your case):用法示例(在您的情况下):

homes.sort(compareBy('city', '-price'));

It should be noted that this function can be even more generalized in order to be able to use nested properties like 'address.city' or 'style.size.width' etc.应该注意的是,这个函数可以更加通用化,以便能够使用嵌套属性,如 'address.city' 或 'style.size.width' 等。

To make things simple, use these helper functions.为简单起见,请使用这些辅助函数。

You can sort by as many fields as you need.您可以根据需要按任意多个字段进行排序。 For each sort field, specify the property name, and then, optionally, specify -1 as the sort direction to sort descending instead of ascending.对于每个排序字段,指定属性名称,然后(可选)指定-1作为排序方向以降序而不是升序。

 const data = [ {"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"}, {"h_id":"7","city":"New York","state":"NY","zip":"00010","price":"800500"} ] const sortLexically = (p,d=1)=>(a,b)=>d * a[p].localeCompare(b[p]) const sortNumerically = (p,d=1)=>(a,b)=>d * (a[p]-b[p]) const sortBy = sorts=>(a,b)=>sorts.reduce((r,s)=>r||s(a,b),0) // sort first by city, then by price descending data.sort(sortBy([sortLexically('city'), sortNumerically('price', -1)])) console.log(data)

Here is a generic version of @Snowburnt's solution:这是@Snowburnt 解决方案的通用版本:

var sortarray = [{field:'city', direction:'asc'}, {field:'price', direction:'desc'}];
array.sort(function(a,b){
    for(var i=0; i<sortarray.length; i++){
        retval = a[sortarray[i].field] < b[sortarray[i].field] ? -1 : a[sortarray[i].field] > b[sortarray[i].field] ? 1 : 0;
        if (sortarray[i].direction == "desc") {
            retval = retval * -1;
        }
        if (retval !== 0) {
            return retval;
        }
    }
}


})

This is based on a sort routine I'm using.这是基于我正在使用的排序例程。 I didn't test this specific code so it may have errors but you get the idea.我没有测试这个特定的代码,所以它可能有错误,但你明白了。 The idea is to sort based on the first field that indicates a difference and then stop and go to the next record.这个想法是根据指示差异的第一个字段进行排序,然后停止并转到下一条记录。 So, if you're sorting by three fields and the first field in the compare is enough to determine the sort order of the two records being sorted then return that sort result and go to the next record.因此,如果您按三个字段排序,并且比较中的第一个字段足以确定要排序的两条记录的排序顺序,则返回该排序结果并转到下一条记录。

I tested it (actually with a little more complex sort logic) on 5000 records and it did it in the blink of an eye.我在 5000 条记录上测试了它(实际上使用了更复杂的排序逻辑),它在眨眼间就完成了。 If you're actually loading more than 1000 records to the client you should probably be using sever-side sorting and filtering.如果您实际上向客户端加载了超过 1000 条记录,您可能应该使用服务器端排序和过滤。

This code isn't handling case-sensitivity but I leave it to the reader to handle this trivial modification.此代码不区分大小写,但我将其留给读者来处理这个微不足道的修改。

function sort(data, orderBy) {
        orderBy = Array.isArray(orderBy) ? orderBy : [orderBy];
        return data.sort((a, b) => {
            for (let i = 0, size = orderBy.length; i < size; i++) {
                const key = Object.keys(orderBy[i])[0],
                    o = orderBy[i][key],
                    valueA = a[key],
                    valueB = b[key];
                if (!(valueA || valueB)) {
                    console.error("the objects from the data passed does not have the key '" + key + "' passed on sort!");
                    return [];
                }
                if (+valueA === +valueA) {
                    return o.toLowerCase() === 'desc' ? valueB - valueA : valueA - valueB;
                } else {
                    if (valueA.localeCompare(valueB) > 0) {
                        return o.toLowerCase() === 'desc' ? -1 : 1;
                    } else if (valueA.localeCompare(valueB) < 0) {
                        return o.toLowerCase() === 'desc' ? 1 : -1;
                    }
                }
            }
        });
    }

Using :使用 :

sort(homes, [{city : 'asc'}, {price: 'desc'}])

 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"} ]; function sort(data, orderBy) { orderBy = Array.isArray(orderBy) ? orderBy : [orderBy]; return data.sort((a, b) => { for (let i = 0, size = orderBy.length; i < size; i++) { const key = Object.keys(orderBy[i])[0], o = orderBy[i][key], valueA = a[key], valueB = b[key]; if (!(valueA || valueB)) { console.error("the objects from the data passed does not have the key '" + key + "' passed on sort!"); return []; } if (+valueA === +valueA) { return o.toLowerCase() === 'desc' ? valueB - valueA : valueA - valueB; } else { if (valueA.localeCompare(valueB) > 0) { return o.toLowerCase() === 'desc' ? -1 : 1; } else if (valueA.localeCompare(valueB) < 0) { return o.toLowerCase() === 'desc' ? 1 : -1; } } } }); } console.log(sort(homes, [{city : 'asc'}, {price: 'desc'}]));

// custom sorting by city
const sortArray = ['Dallas', 'New York', 'Beverly Hills'];

const sortData = (sortBy) =>
  data
    .sort((a, b) => {
      const aIndex = sortBy.indexOf(a.city);
      const bIndex = sortBy.indexOf(b.city);

      if (aIndex < bIndex) {
        return -1;
      }

      if (aIndex === bIndex) {
        // price descending
        return b.price- a.price;
      }

      return 1;
    });

sortData(sortArray);

simply follow the list of your sorting criteria只需按照您的排序标准列表

this code will always remain readable and understandable even if you have 36 sorting criteria to encase即使您有 36 个排序标准要封装,此代码也将始终保持可读性和可理解性

The solution proposed here by Nina is certainly very elegant, but it implies knowing that a value of zero corresponds to a value of false in Boolean logic, and that Boolean tests can return something other than true / false in JavaScript (here are numeric values) which will always be confusing for a beginner. Nina 在这里提出的解决方案当然非常优雅,但它意味着知道值为零对应于布尔逻辑中的 false 值,并且布尔测试可以在 JavaScript 中返回除 true/false 以外的值(这里是数字值)这对于初学者来说总是令人困惑。

Also think about who will need to maintain your code.还要考虑谁需要维护您的代码。 Maybe it would be you: imagine yourself spending your days raking for days the code of another and having a pernicious bug ... and you are exhausted from reading these thousands of lines full of tips也许会是你:想象你自己花了几天的时间来搜索另一个人的代码并且遇到了一个有害的错误......并且你已经厌倦了阅读这数千行充满提示的行

 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))

Adding a couple helper functions lets you solved this kind of problem generically and simply.添加几个辅助函数可以让您通用且简单地解决此类问题。 sortByKey takes an array and a function which should return a list of items with which to compare each array entry. sortByKey接受一个数组和一个函数,该函数应该返回一个项目列表,用于比较每个数组条目。

This takes advantage of the fact that javascript does smart comparison of arrays of simple values, with [0] < [0, 0] < [0, 1] < [1, 0] .这利用了 javascript 对简单值数组进行智能比较的事实,即[0] < [0, 0] < [0, 1] < [1, 0]


// Two helpers:
function cmp(a, b) {
    if (a > b) {
        return 1
    } else if (a < b) {
        return -1
    } else {
        return 0
    }
}

function sortByKey(arr, key) {
    arr.sort((a, b) => cmp(key(a), key(b)))
}

// A demonstration:
let arr = [{a:1, b:2}, {b:3, a:0}, {a:1, b:1}, {a:2, b:2}, {a:2, b:1}]
sortByKey(arr, item => [item.a, item.b])

console.log(JSON.stringify(arr))
// '[{"b":3,"a":0},{"a":1,"b":1},{"a":1,"b":2},{"a":2,"b":1},{"a":2,"b":2}]'

sortByKey(arr, item => [item.b, item.a])
console.log(JSON.stringify(arr))
//'[{"a":1,"b":1},{"a":2,"b":1},{"a":1,"b":2},{"a":2,"b":2},{"b":3,"a":0}]'

I've lovingly stolen this idea from Python's list.sort function.我从 Python 的list.sort函数中巧妙地窃取了这个想法。

function sortMultiFields(prop){
    return function(a,b){
        for(i=0;i<prop.length;i++)
        {
            var reg = /^\d+$/;
            var x=1;
            var field1=prop[i];
            if(prop[i].indexOf("-")==0)
            {
                field1=prop[i].substr(1,prop[i].length);
                x=-x;
            }

            if(reg.test(a[field1]))
            {
                a[field1]=parseFloat(a[field1]);
                b[field1]=parseFloat(b[field1]);
            }
            if( a[field1] > b[field1])
                return x;
            else if(a[field1] < b[field1])
                return -x;
        }
    }
}

How to use (put -(minus) sign before field if you want to sort in descending order particular field)如何使用(如果要按降序对特定字段进行排序,请在字段前放置 -(减号)符号)

homes.sort(sortMultiFields(["city","-price"]));

Using above function you can sort any json array with multiple fields.使用上述函数,您可以对具有多个字段的任何 json 数组进行排序。 No need to change function body at all完全不需要改变函数体

Adaptation of @chriskelly 's answer.改编@chriskelly 的答案。


Most answers overlook that price will not sort properly if the value is in the ten thousands and lower or over a million.大多数答案忽略了如果价值在万以下或超过一百万,价格将无法正确排序。 The resaon being JS sorts alphabetically. JS 的原因是按字母顺序排序。 It was answered pretty well here, Why can't JavaScript sort "5, 10, 1" and here How to sort an array of integers correctly .在这里回答得很好,为什么 JavaScript 不能对 "5, 10, 1"进行排序,在这里如何正确地对整数数组进行排序

Ultimately we have to do some evaluation if the field or node we're sorting by is an number.如果我们排序的字段或节点是一个数字,最终我们必须做一些评估。 I am not saying that using parseInt() in this case is the correct answer, the sorted results are more important.我并不是说在这种情况下使用parseInt()是正确的答案,排序结果更重要。

 var homes = [{ "h_id": "2", "city": "Dallas", "state": "TX", "zip": "75201", "price": "62500" }, { "h_id": "1", "city": "Dallas", "state": "TX", "zip": "75201", "price": "62510" }, { "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" }]; homes.sort(fieldSorter(['price'])); // homes.sort(fieldSorter(['zip', '-state', 'price'])); // alternative function fieldSorter(fields) { return function(a, b) { return fields .map(function(o) { var dir = 1; if (o[0] === '-') { dir = -1; o = o.substring(1); } if (!parseInt(a[o]) && !parseInt(b[o])) { if (a[o] > b[o]) return dir; if (a[o] < b[o]) return -(dir); return 0; } else { return dir > 0 ? a[o] - b[o] : b[o] - a[o]; } }) .reduce(function firstNonZeroValue(p, n) { return p ? p : n; }, 0); }; } document.getElementById("output").innerHTML = '<pre>' + JSON.stringify(homes, null, '\t') + '</pre>';
 <div id="output"> </div>


A fiddle to test with一个要测试的小提琴

Wow, there are some complex solutions here.哇,这里有一些复杂的解决方案。 So complex I decided to come up with something simpler but also quite powerful.如此复杂,我决定想出一些更简单但也很强大的东西。 Here it is;这里是;

function sortByPriority(data, priorities) {
  if (priorities.length == 0) {
    return data;
  }

  const nextPriority = priorities[0];
  const remainingPriorities = priorities.slice(1);

  const matched = data.filter(item => item.hasOwnProperty(nextPriority));
  const remainingData = data.filter(item => !item.hasOwnProperty(nextPriority));

  return sortByPriority(matched, remainingPriorities)
    .sort((a, b) => (a[nextPriority] > b[nextPriority]) ? 1 : -1)
    .concat(sortByPriority(remainingData, remainingPriorities));
}

And here is an example of how you use it.这是一个如何使用它的示例。

const data = [
  { id: 1,                         mediumPriority: 'bbb', lowestPriority: 'ggg' },
  { id: 2, highestPriority: 'bbb', mediumPriority: 'ccc', lowestPriority: 'ggg' },
  { id: 3,                         mediumPriority: 'aaa', lowestPriority: 'ggg' },
];

const priorities = [
  'highestPriority',
  'mediumPriority',
  'lowestPriority'
];


const sorted = sortByPriority(data, priorities);

This will first sort by the precedence of the attributes, then by the value of the attributes.这将首先按属性的优先级排序,然后按属性的值。

I think this may be the easiest way to do it.我认为这可能是最简单的方法。

https://coderwall.com/p/ebqhca/javascript-sort-by-two-fieldshttps://coderwall.com/p/ebqhca/javascript-sort-by-two-fields

It's really simple and I tried it with 3 different key value pairs and it worked great.这真的很简单,我尝试了 3 个不同的键值对,效果很好。

Here is a simple example, look at the link for more details这是一个简单的例子,查看链接了解更多详情

testSort(data) {
    return data.sort(
        a['nameOne'] > b['nameOne'] ? 1
        : b['nameOne'] > a['nameOne'] ? -1 : 0 ||
        a['date'] > b['date'] ||
        a['number'] - b['number']
    );
}

Here is mine for your reference, with example:这是我的供您参考,例如:

function msort(arr, ...compFns) {
  let fn = compFns[0];
  arr = [].concat(arr);
  let arr1 = [];
  while (arr.length > 0) {
    let arr2 = arr.splice(0, 1);
    for (let i = arr.length; i > 0;) {
      if (fn(arr2[0], arr[--i]) === 0) {
        arr2 = arr2.concat(arr.splice(i, 1));
      }
    }
    arr1.push(arr2);
  }

  arr1.sort(function (a, b) {
    return fn(a[0], b[0]);
  });

  compFns = compFns.slice(1);
  let res = [];
  arr1.map(a1 => {
    if (compFns.length > 0) a1 = msort(a1, ...compFns);
    a1.map(a2 => res.push(a2));
  });
  return res;
}

let tstArr = [{ id: 1, sex: 'o' }, { id: 2, sex: 'm' }, { id: 3, sex: 'm' }, { id: 4, sex: 'f' }, { id: 5, sex: 'm' }, { id: 6, sex: 'o' }, { id: 7, sex: 'f' }];

function tstFn1(a, b) {
  if (a.sex > b.sex) return 1;
  else if (a.sex < b.sex) return -1;
  return 0;
}

function tstFn2(a, b) {
  if (a.id > b.id) return -1;
  else if (a.id < b.id) return 1;
  return 0;
}

console.log(JSON.stringify(msort(tstArr, tstFn1, tstFn2)));
//output:
//[{"id":7,"sex":"f"},{"id":4,"sex":"f"},{"id":5,"sex":"m"},{"id":3,"sex":"m"},{"id":2,"sex":"m"},{"id":6,"sex":"o"},{"id":1,"sex":"o"}]

I was looking for something similar and ended up with this:我一直在寻找类似的东西并最终得到了这个:

First we have one or more sorting functions, always returning either 0, 1 or -1:首先,我们有一个或多个排序函数,总是返回 0、1 或 -1:

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

You can create more functions for each other property you want to sort on.您可以为要排序的每个其他属性创建更多函数。

Then I have a function that combines these sorting functions into one:然后我有一个函数将这些排序函数合二为一:

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

This can be used to combine the above sorting functions in a readable way:这可以用来以一种可读的方式组合上述排序函数:

const sorter = createSorter(sortByTitle, sortByYear)

items.sort(sorter)

When a sorting function returns 0 the next sorting function will be called for further sorting.当排序函数返回 0 时,将调用下一个排序函数进行进一步排序。

This is a recursive algorithm to sort by multiple fields while having the chance to format values before comparison.这是一种递归算法,用于按多个字段排序,同时有机会在比较之前格式化值。

var data = [
{
    "id": 1,
    "ship": null,
    "product": "Orange",
    "quantity": 7,
    "price": 92.08,
    "discount": 0
},
{
    "id": 2,
    "ship": "2017-06-14T23:00:00.000Z".toDate(),
    "product": "Apple",
    "quantity": 22,
    "price": 184.16,
    "discount": 0
},
...
]
var sorts = ["product", "quantity", "ship"]

// comp_val formats values and protects against comparing nulls/undefines
// type() just returns the variable constructor
// String.lower just converts the string to lowercase.
// String.toDate custom fn to convert strings to Date
function comp_val(value){
    if (value==null || value==undefined) return null
    var cls = type(value)
    switch (cls){
        case String:
            return value.lower()
    }
    return value
}

function compare(a, b, i){
    i = i || 0
    var prop = sorts[i]
    var va = comp_val(a[prop])
    var vb = comp_val(b[prop])

    // handle what to do when both or any values are null
    if (va == null || vb == null) return true

    if ((i < sorts.length-1) && (va == vb)) {
        return compare(a, b, i+1)
    } 
    return va > vb
}

var d = data.sort(compare);
console.log(d);

If a and b are equal it will just try the next field until none is available.如果 a 和 b 相等,它将只尝试下一个字段,直到没有可用的字段。

You can use lodash orderBy function lodash您可以使用 lodash orderBy 函数lodash

It takes two params array of fields, and array of directions ('asc','desc')它需要两个参数字段数组和方向数组('asc','desc')

  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"}
    ];

var sorted =. data._.orderBy(data, ['city', 'price'], ['asc','desc'])

A very intuitive functional solution can be crafted by adding 3 relatively simple helpers.通过添加 3 个相对简单的助手可以制作一个非常直观的功能解决方案。 Before we dive in, let's start with the usage:在我们深入研究之前,让我们从用法开始:

 function usage(homes, { asc, desc, fallback }) { homes.sort(fallback( asc(home => home.city), desc(home => parseInt(home.price, 10)), )); console.log(homes); } 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", }]; const SortHelpers = (function () { const asc = (fn) => (a, b) => (a = fn(a), b = fn(b), -(a < b) || +(a > b)); const desc = (fn) => (a, b) => asc(fn)(b, a); const fallback = (...fns) => (a, b) => fns.reduce((diff, fn) => diff || fn(a, b), 0); return { asc, desc, fallback }; })(); usage(homes, SortHelpers);

If you scrolled down the snippet you probably already saw the helpers:如果您向下滚动代码段,您可能已经看到了帮助程序:

const asc  = (fn) => (a, b) => (a = fn(a), b = fn(b), -(a < b) || +(a > b));
const desc = (fn) => (a, b) => asc(fn)(b, a);
const fallback = (...fns) => (a, b) => fns.reduce((diff, fn) => diff || fn(a, b), 0);

Let me quickly explain what each of these functions does.让我快速解释一下每个函数的作用。

  • asc creates a comparator function. asc创建一个比较器函数。 The provided function fn is called with both the comparator arguments a and b .使用比较器参数ab调用提供的函数fn The results of the two function calls are then compared.然后比较两个函数调用的结果。 -1 is returned if resultA < resultB , 1 is returned if resultA > resultB , or 0 if both are false.如果resultA < resultB则返回-1 ,如果resultA > resultB则返回1 ,如果两者都为 false 则返回0 These return values correspond with an ascending order direction.这些返回值对应于升序方向。

    It could also be written like this:也可以这样写:

     function asc(fn) { return function (a, b) { // apply `fn` to both `a` and `b` a = fn(a); b = fn(b); if (a < b) return -1; if (a > b) return 1; return 0; // or `return -(a < b) || +(a > b)` for short }; }
  • desc is super simple, since it just calls asc but swaps the a and b arguments, resulting in descending order instead of ascending. desc非常简单,因为它只是调用asc但交换了ab参数,从而导致降序而不是升序。

  • fallback (there might be a better name for this) allows us to use multiple comparator functions with a single sort . fallback (可能有一个更好的名字)允许我们使用多个比较器函数和一个sort

    Both asc and desc can be passed to sort by themself. ascdesc都可以传递给自己sort

     homes.sort(asc(home => home.city))

    There is however an issue if you want to combine multiple comparator functions.但是,如果您想组合多个比较器功能,则会出现问题。 sort only accepts a single comparator function. sort只接受一个比较器函数。 fallback combines multiple comparator functions into a single comparator. fallback将多个比较器功能组合到一个比较器中。

    The first comparator is called with arguments a and b , if the comparator returns the value 0 (meaning that the values are equal) then we fall back to the next comparator.第一个比较器使用参数ab调用,如果比较器返回值0 (意味着值相等),那么我们回退到下一个比较器。 This continues until a non- 0 value is found, or until all comparators are called, in which case the return value is 0 .这一直持续到找到非0值,或者直到调用所有比较器,在这种情况下,返回值为0

You provide your custom comparator functions super simple.您提供了超级简单的自定义比较器功能。 Say you want to use localeCompare() instead of comparing strings with < and > .假设您想使用localeCompare()而不是将字符串与<>进行比较。 In such a case you can simply replace asc(home => home.city) with (a, b) => a.city.localeCompare(b.city) .在这种情况下,您可以简单地将asc(home => home.city)替换为(a, b) => a.city.localeCompare(b.city)

homes.sort(fallback(
  (a, b) => a.city.localeCompare(b.city),
  desc(home => parseInt(home.price, 10)),
));

One thing to note is that values that can be undefined will always return false when comparing with < and > .需要注意的一件事是,与<>进行比较时,可以undefined的值将始终返回false So if a value can be missing you might want to sort by its presence first.因此,如果一个值可能丢失,您可能需要先按其存在进行排序。

homes.sort(fallback(
  // homes with optionalProperty first, true (1) > false (0) so we use desc
  desc(home => home.optionalProperty != null), // checks for both null and undefined
  asc(home => home.optionalProperty),
  // ...
))

Since 2019 all major Javascript engines implement stable Array.sort .自 2019 年以来,所有主要的 Javascript 引擎都实现了稳定的 Array.sort What this essentially means is that each time we sort by property a , items with identical properties b will go in the same order.这本质上意味着每次我们按属性a排序时,具有相同属性b的项目将按相同的顺序排列。 Thanks to this, we could do the following:多亏了这一点,我们可以做到以下几点:

 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 byCityAscending = (a, b) => a.city.localeCompare(b.city); const byPriceDescending = (a, b) => parseFloat(b.price) - parseFloat(a.price); const result = homes.sort(byPriceDescending).sort(byCityAscending) console.log(result)

⚠️ Please note that we apply the sorting functions in reverse order . ⚠️ 请注意,我们以相反的顺序应用排序功能。 If you think of it, this makes sense — chaining still happens left to right, but we "unfold" the sorting from inside.如果您考虑一下,这是有道理的——链接仍然从左到右发生,但我们从内部“展开”排序。 First we stabilise the inmost items order.首先我们稳定最里面的物品顺序。 Then, thanks to stable sorting, that order is preserved when we get identical values during outer sorting.然后,由于稳定​​的排序,当我们在外部排序期间获得相同的值时,该顺序得以保留。

Here, you can try the smaller and convenient way to sort by multiple fields!在这里,您可以尝试按多个字段排序的更小更方便的方式!

 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"} ]; homes.sort((a, b)=> { if (a.city === b.city){ return a.price < b.price? -1: 1 } else { return a.city < b.city? -1: 1 } }) console.log(homes);

Here 'AffiliateDueDate' and 'Title' are columns, both are sorted in ascending order.这里 'AffiliateDueDate' 和 'Title' 是列,都按升序排序。

array.sort(function(a, b) {

               if (a.AffiliateDueDate > b.AffiliateDueDate ) return 1;
               else if (a.AffiliateDueDate < b.AffiliateDueDate ) return -1;
               else if (a.Title > b.Title ) return 1;
               else if (a.Title < b.Title ) return -1;
               else return 0;
             })

Sorting on two date fields and a numeric field example:对两个日期字段和一个数字字段示例进行排序:

var generic_date =  new Date(2070, 1, 1);
checkDate = function(date) {
  return Date.parse(date) ? new Date(date): generic_date;
}

function sortData() {  
  data.sort(function(a,b){
    var deltaEnd = checkDate(b.end) - checkDate(a.end);
    if(deltaEnd) return deltaEnd;

    var deltaRank = a.rank - b.rank;
    if (deltaRank) return deltaRank;

    var deltaStart = checkDate(b.start) - checkDate(a.start);
    if(deltaStart) return deltaStart;

    return 0;
  });
}

http://jsfiddle.net/hcWgf/57/ http://jsfiddle.net/hcWgf/57/

How about this simple solution:这个简单的解决方案怎么样:

const sortCompareByCityPrice = (a, b) => {
    let comparison = 0
    // sort by first criteria
    if (a.city > b.city) {
        comparison = 1
    }
    else if (a.city < b.city) {
        comparison = -1
    }
    // If still 0 then sort by second criteria descending
    if (comparison === 0) {
        if (parseInt(a.price) > parseInt(b.price)) {
            comparison = -1
        }
        else if (parseInt(a.price) < parseInt(b.price)) {
            comparison = 1
        }
    }
    return comparison 
}

Based on this question javascript sort array by multiple (number) fields基于this question javascript sort array by multiple (number) fields

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

Simplest Way to sort array of object by multiple fields:按多个字段对对象数组进行排序的最简单方法:

 let 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"}
  ];

homes.sort((a, b) => (a.city > b.city) ? 1 : -1);

Output: "Bevery Hills" "Dallas" "Dallas" "Dallas" "New York"输出:“Bevery Hills”“Dallas”“Dallas”“Dallas”“New York”

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM