按属性值对对象数组进行排序

1693

我使用AJAX获取了以下对象并将它们存储在一个数组中:

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": "5",
        "city": "New York",
        "state": "NY",
        "zip": "00010",
        "price": "962500"
    }
];

如何使用JavaScript创建一个按照对象的price属性以升序降序排序的函数?


最快的方法是使用isomorphic sort-array模块,它在浏览器和Node中都可以本地运行,支持任何类型的输入、计算字段和自定义排序顺序。 - Lloyd
相关:按对象属性值对数组进行数字排序 - Sebastian Simon
35个回答

11

价格按降序排列:

homes.sort((x,y) => {return y.price - x.price})

价格升序:

homes.sort((x,y) => {return x.price - y.price})

10

通过一个简单的一行代码valueof()排序函数就可以实现这一点。运行下面的代码片段以查看演示。

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": "5",
        "city": "New York",
        "state": "NY",
        "zip": "00010",
        "price": "962500"
    }
];

console.log("To sort descending/highest first, use operator '<'");

homes.sort(function(a,b) { return a.price.valueOf() < b.price.valueOf();});

console.log(homes);

console.log("To sort ascending/lowest first, use operator '>'");

homes.sort(function(a,b) { return a.price.valueOf() > b.price.valueOf();});

console.log(homes);


在我看來,價格看起來是從低到高排序的。 - vapcguy

10

虽然我知道OP想要对数字数组进行排序,但这个问题被标记为类似于字符串的问题的答案。因此,上面的答案没有考虑到大小写很重要的文本数组排序。大多数答案将字符串值转换为大写/小写,然后以某种方式排序。我所遵循的要求很简单:

  • 按字母顺序A-Z排序
  • 相同单词的大写值应该在小写值之前
  • 相同的字母(A/a,B/b)值应该被分组在一起

我期望的结果是[ A, a, B, b, C, c ],但以上答案返回A, B, C, a, b, c 。我实际上花了比想象中更长的时间来思考这个问题(这也是我希望发布这篇帖子以帮助至少一个人)。虽然有两个用户在评论中提到了localeCompare函数,但在我搜索的过程中,直到我偶然发现该函数,我才看到这些评论。阅读String.prototype.localeCompare()文档后,我得出了以下结论:

var values = [ "Delta", "charlie", "delta", "Charlie", "Bravo", "alpha", "Alpha", "bravo" ];
var sorted = values.sort((a, b) => a.localeCompare(b, undefined, { caseFirst: "upper" }));
// Result: [ "Alpha", "alpha", "Bravo", "bravo", "Charlie", "charlie", "Delta", "delta" ]

这个函数告诉程序先将大写字母排序,再将小写字母排序。在localeCompare函数的第二个参数中,可以定义语言环境,但如果将其设置为undefined,它会自动为您确定语言环境。

对于对象数组的排序也是同样的:

var values = [
    { id: 6, title: "Delta" },
    { id: 2, title: "charlie" },
    { id: 3, title: "delta" },
    { id: 1, title: "Charlie" },
    { id: 8, title: "Bravo" },
    { id: 5, title: "alpha" },
    { id: 4, title: "Alpha" },
    { id: 7, title: "bravo" }
];
var sorted = values
    .sort((a, b) => a.title.localeCompare(b.title, undefined, { caseFirst: "upper" }));

8
以下是所有答案的总结:
Fiddle验证: http://jsfiddle.net/bobberino/4qqk3/
var sortOn = function (arr, prop, reverse, numeric) {

    // Ensure there's a property
    if (!prop || !arr) {
        return arr
    }

    // Set up sort function
    var sort_by = function (field, rev, primer) {

        // Return the required a,b function
        return function (a, b) {

            // Reset a, b to the field
            a = primer(a[field]), b = primer(b[field]);

            // Do actual sorting, reverse as needed
            return ((a < b) ? -1 : ((a > b) ? 1 : 0)) * (rev ? -1 : 1);
        }

    }

    // Distinguish between numeric and string to prevent 100's from coming before smaller
    // e.g.
    // 1
    // 20
    // 3
    // 4000
    // 50

    if (numeric) {

        // Do sort "in place" with sort_by function
        arr.sort(sort_by(prop, reverse, function (a) {

            // - Force value to a string.
            // - Replace any non numeric characters.
            // - Parse as float to allow 0.02 values.
            return parseFloat(String(a).replace(/[^0-9.-]+/g, ''));

        }));
    } else {

        // Do sort "in place" with sort_by function
        arr.sort(sort_by(prop, reverse, function (a) {

            // - Force value to string.
            return String(a).toUpperCase();

        }));
    }


}

请问您能否解释一下在代码中使用 * (rev ? -1 : 1) 的意义是什么? - TechTurtle
这是为了反转顺序(升序 vs 降序),rev 部分只是在 rev 参数为 true 时翻转正常结果。否则它只会乘以 1,什么也不做,当设置时,它将把结果乘以 -1,从而反转结果。 - bob

7

要对数组进行排序,您必须定义一个比较函数。该函数的不同之处在于您所需的排序模式或顺序(即升序或降序)。

让我们创建一些函数,以升序或降序排序包含对象、字符串或数字值的数组。

function sorterAscending(a,b) {
    return a-b;
}

function sorterDescending(a,b) {
    return b-a;
}

function sorterPriceAsc(a,b) {
    return parseInt(a['price']) - parseInt(b['price']);
}

function sorterPriceDes(a,b) {
    return parseInt(b['price']) - parseInt(b['price']);
}

对数字进行排序(按字母顺序和升序):

var fruits = ["Banana", "Orange", "Apple", "Mango"];
fruits.sort();

排序数字(按字母顺序和降序):

var fruits = ["Banana", "Orange", "Apple", "Mango"];
fruits.sort();
fruits.reverse();

按数字大小升序排列:

var points = [40,100,1,5,25,10];
points.sort(sorterAscending());

对数字进行排序(按照数值降序排列):

var points = [40,100,1,5,25,10];
points.sort(sorterDescending());

使用sorterPriceAsc和sorterPriceDes方法与所需键的数组进行排序,如上所述。
homes.sort(sorterPriceAsc()) or homes.sort(sorterPriceDes())

7
更类似于 LINQ 的解决方案:
Array.prototype.orderBy = function (selector, desc = false) {
    return [...this].sort((a, b) => {
        a = selector(a);
        b = selector(b);

        if (a == b) return 0;
        return (desc ? a > b : a < b) ? -1 : 1;
    });
}

优点:

  • 属性自动完成
  • 扩展数组原型
  • 不改变数组本身
  • 易于在方法链中使用

用法:

Array.prototype.orderBy = function(selector, desc = false) {
  return [...this].sort((a, b) => {
    a = selector(a);
    b = selector(b);

    if (a == b) return 0;
    return (desc ? a > b : a < b) ? -1 : 1;
  });
};

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": "5",
  "city": "New York",
  "state": "NY",
  "zip": "00010",
  "price": "962500"
}];

let sorted_homes = homes.orderBy(h => parseFloat(h.price));
console.log("sorted by price", sorted_homes);

let sorted_homes_desc = homes.orderBy(h => h.city, true);
console.log("sorted by City descending", sorted_homes_desc);


6
您可以使用JavaScript的sort方法,并搭配回调函数使用:
function compareASC(homeA, homeB)
{
    return parseFloat(homeA.price) - parseFloat(homeB.price);
}

function compareDESC(homeA, homeB)
{
    return parseFloat(homeB.price) - parseFloat(homeA.price);
}

// Sort ASC
homes.sort(compareASC);

// Sort DESC
homes.sort(compareDESC);

5

使用 ECMAScript 6,StoBor 的答案可以更加简洁:

homes.sort((a, b) => a.price - b.price)

5

使用此函数

const r_sort = (a, b, field, asc) => {
    let reverse = asc ? 1 : -1;
    if (a[field] > b[field]) {
        return 1 * reverse;
    }
    else if (b[field] > a[field]) {
        return -1 * reverse;
    }
    else {
        return 0;
    } }

//使用方法:

homes = homes.sort((a,b) => r_sort(a,b,price,true)) // true for ascending and false for descending

5

虽然对于只需要对一个数组进行排序来说有些太过复杂,但这个原型函数可以通过使用点号语法以升序或降序的方式按任何键对Javascript数组进行排序,包括嵌套键

(function(){
    var keyPaths = [];

    var saveKeyPath = function(path) {
        keyPaths.push({
            sign: (path[0] === '+' || path[0] === '-')? parseInt(path.shift()+1) : 1,
            path: path
        });
    };

    var valueOf = function(object, path) {
        var ptr = object;
        for (var i=0,l=path.length; i<l; i++) ptr = ptr[path[i]];
        return ptr;
    };

    var comparer = function(a, b) {
        for (var i = 0, l = keyPaths.length; i < l; i++) {
            aVal = valueOf(a, keyPaths[i].path);
            bVal = valueOf(b, keyPaths[i].path);
            if (aVal > bVal) return keyPaths[i].sign;
            if (aVal < bVal) return -keyPaths[i].sign;
        }
        return 0;
    };

    Array.prototype.sortBy = function() {
        keyPaths = [];
        for (var i=0,l=arguments.length; i<l; i++) {
            switch (typeof(arguments[i])) {
                case "object": saveKeyPath(arguments[i]); break;
                case "string": saveKeyPath(arguments[i].match(/[+-]|[^.]+/g)); break;
            }
        }
        return this.sort(comparer);
    };    
})();

使用方法:

var data = [
    { name: { first: 'Josh', last: 'Jones' }, age: 30 },
    { name: { first: 'Carlos', last: 'Jacques' }, age: 19 },
    { name: { first: 'Carlos', last: 'Dante' }, age: 23 },
    { name: { first: 'Tim', last: 'Marley' }, age: 9 },
    { name: { first: 'Courtney', last: 'Smith' }, age: 27 },
    { name: { first: 'Bob', last: 'Smith' }, age: 30 }
]

data.sortBy('age'); // "Tim Marley(9)", "Carlos Jacques(19)", "Carlos Dante(23)", "Courtney Smith(27)", "Josh Jones(30)", "Bob Smith(30)"

使用点语法或数组语法按嵌套属性进行排序:

data.sortBy('name.first'); // "Bob Smith(30)", "Carlos Dante(23)", "Carlos Jacques(19)", "Courtney Smith(27)", "Josh Jones(30)", "Tim Marley(9)"
data.sortBy(['name', 'first']); // "Bob Smith(30)", "Carlos Dante(23)", "Carlos Jacques(19)", "Courtney Smith(27)", "Josh Jones(30)", "Tim Marley(9)"

按多个键排序:
data.sortBy('name.first', 'age'); // "Bob Smith(30)", "Carlos Jacques(19)", "Carlos Dante(23)", "Courtney Smith(27)", "Josh Jones(30)", "Tim Marley(9)"
data.sortBy('name.first', '-age'); // "Bob Smith(30)", "Carlos Dante(23)", "Carlos Jacques(19)", "Courtney Smith(27)", "Josh Jones(30)", "Tim Marley(9)"

你可以fork这个仓库:https://github.com/eneko/Array.sortBy

我非常喜欢这个答案,因为sortBy的语法简洁明了。它易于使用,即使在嵌套字段的情况下也是如此,同时保持了良好的代码可读性。谢谢! - Manfred Urban

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接