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

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

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

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

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


当前回答

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

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

其他回答

通过添加两个辅助函数,可以简单地解决这类问题。sortByKey接受一个数组和一个函数,该函数应返回一个项目列表,用于与每个数组条目进行比较。

这利用了javascript对简单值的数组进行智能比较的事实,即[2]<[2,0]<[2,1]<[10,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}, {a:1, b:10}] sortByKey(arr, item => [item.a, item.b]) console.log(JSON.stringify(arr)) // '[{"b":3,"a":0},{"a":1,"b":1},{"a":1,"b":10},{"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":10},{"a":1,"b":2},{"a":2,"b":2},{"b":3,"a":0}]'

我从Python的列表中偷取了这个想法。排序功能。

另一种方式

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

这是一个递归算法,按多个字段排序,同时有机会在比较之前格式化值。

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

如果a和b相等,它将尝试下一个字段,直到没有可用字段。

只是另一种选择。考虑使用以下效用函数:

/** 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;
};

用法示例(在您的情况下):

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

值得注意的是,这个函数可以更一般化,以便能够使用嵌套属性,如'address '。City '或'style.size。宽度”等。

以下是@ snowburn的解决方案的通用版本:

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


})

这是基于我正在使用的排序例程。我没有测试这个特定的代码,所以它可能有错误,但你知道的。其思想是基于第一个表示差异的字段进行排序,然后停止并转到下一个记录。因此,如果您按三个字段排序,并且compare中的第一个字段足以确定正在排序的两个记录的排序顺序,那么将返回该排序结果并转到下一个记录。

我在5000条记录上测试了它(实际上使用了更复杂的排序逻辑),它在眨眼之间就做到了。如果实际向客户端加载超过1000条记录,则可能应该使用服务器端排序和过滤。

这段代码不区分大小写,我把它留给读者来处理这个微不足道的修改。