462

我有一个对象列表,我希望根据attr字符串类型的字段进行排序。我尝试使用-

list.sort(function (a, b) {
    return a.attr - b.attr
})

但发现这-似乎不适用于 JavaScript 中的字符串。如何根据字符串类型的属性对对象列表进行排序?

4

16 回答 16

814

String.prototype.localeCompare根据您的示例使用:

list.sort(function (a, b) {
    return ('' + a.attr).localeCompare(b.attr);
})

我们强制 a.attr 为字符串以避免异常。自 Internet Explorer 6localeCompare和 Firefox 1起已受支持。您可能还会看到使用的以下代码不尊重语言环境:

if (item1.attr < item2.attr)
  return -1;
if ( item1.attr > item2.attr)
  return 1;
return 0;
于 2008-09-09T03:29:17.300 回答
195

更新的答案(2014 年 10 月)

我对这个字符串自然排序顺序感到非常恼火,所以我花了一些时间来调查这个问题。我希望这有帮助。

长话短说

localeCompare()角色支持很糟糕,只需使用它。正如所指出的Shog9,您的问题的答案是:

return item1.attr.localeCompare(item2.attr);

在所有自定义 javascript“自然字符串排序顺序”实现中发现的错误

那里有很多自定义实现,试图更精确地进行字符串比较,称为“自然字符串排序顺序”

在“玩”这些实现时,我总是注意到一些奇怪的“自然排序”选择,或者更确切地说是错误(或者在最好的情况下是遗漏)。

通常,无法正确处理特殊字符(空格、破折号、与号、括号等)。

然后,您会发现它们在不同的地方混杂在一起,通常可能是:

  • 有些会在大写“Z”和小写“a”之间
  • 有些会在“9”和大写“A”之间
  • 有些会在小写“z”之后

当人们期望特殊字符全部“组合”在一个地方时,可能除了空格特殊字符(它始终是第一个字符)。也就是说,要么全部在数字之前,要么全部在数字和字母之间(小写和大写一个接一个地“在一起”),或者全部在字母之后。

我的结论是,当我开始添加几乎不常见的字符(即带有变音符号或破折号、感叹号等字符的字符)时,它们都无法提供一致的顺序。

定制实现的研究:

浏览器的原生“自然字符串排序顺序”实现通过localeCompare()

localeCompare()IE6+ 支持最旧的实现(没有语言环境和选项参数),请参阅http://msdn.microsoft.com/en-us/library/ie/s4esdbwz (v=vs.94).aspx(向下滚动到 localeCompare( ) 方法)。内置localeCompare()方法在排序方面做得更好,甚至是国际和特殊字符。使用该localeCompare()方法的唯一问题是“使用的语言环境和排序顺序完全依赖于实现”。换句话说,当使用诸如 stringOne.localeCompare(stringTwo) 之类的 localeCompare 时:Firefox、Safari、Chrome 和 IE 对字符串有不同的排序顺序。

浏览器原生实现的研究:

“字符串自然排序顺序”的难点

实现一个可靠的算法(意思是:一致但也涵盖广泛的字符)是一项非常艰巨的任务。UTF8 包含超过 2000 个字符涵盖超过 120 种脚本(语言)。最后,此任务有一些规范,称为“Unicode 排序算法”,可在http://www.unicode.org/reports/tr10/找到。您可以在我发布的这个问题上找到更多信息https://softwareengineering.stackexchange.com/questions/257286/is-there-any-language-agnostic-specification-for-string-natural-sorting-order

定论

因此,考虑到我遇到的 javascript 自定义实现提供的当前支持水平,我们可能永远不会看到任何接近支持所有这些字符和脚本(语言)的东西。因此,我宁愿使用浏览器的本地 localeCompare() 方法。是的,它确实具有跨浏览器不一致的缺点,但基本测试表明它涵盖了更广泛的字符,允许可靠且有意义的排序顺序。

正如 所指出的Shog9,您的问题的答案是:

return item1.attr.localeCompare(item2.attr);

进一步阅读:

感谢 Shog9 的好回答,我相信这让我朝着“正确”的方向前进

于 2014-10-10T08:39:42.707 回答
68

答案(在现代 ECMAScript 中)

list.sort((a, b) => (a.attr > b.attr) - (a.attr < b.attr))

或者

list.sort((a, b) => +(a.attr > b.attr) || -(a.attr < b.attr))

描述

将布尔值转换为数字会产生以下结果:

  • true->1
  • false->0

考虑三种可能的模式:

  • x 大于 y: (x > y) - (y < x)-> 1 - 0->1
  • x 等于 y:(x > y) - (y < x)-> 0 - 0->0
  • x 小于 y: (x > y) - (y < x)-> 0 - 1->-1

(选择)

  • x 大于 y: +(x > y) || -(x < y)-> 1 || 0->1
  • x 等于 y:+(x > y) || -(x < y)-> 0 || 0->0
  • x 小于 y: +(x > y) || -(x < y)-> 0 || -1->-1

所以这些逻辑等价于典型的排序比较器函数。

if (x == y) {
    return 0;
}
return x > y ? 1 : -1;
于 2016-11-01T06:28:02.517 回答
19

由于字符串可以直接在 javascript 中进行比较,这将完成这项工作

list.sort(function (a, b) {
    return a.attr > b.attr ? 1: -1;
})

排序函数中的减法仅在需要非字母(数字)排序时使用,当然它不适用于字符串

于 2019-09-22T13:34:01.940 回答
14

您应该在此处使用 > 或 < 和 ==。所以解决方案是:

list.sort(function(item1, item2) {
    var val1 = item1.attr,
        val2 = item2.attr;
    if (val1 == val2) return 0;
    if (val1 > val2) return 1;
    if (val1 < val2) return -1;
});
于 2008-09-09T03:29:42.930 回答
10

嵌套三元箭头函数

(a,b) => (a < b ? -1 : a > b ? 1 : 0)
于 2019-03-14T01:55:29.977 回答
7

我为此困扰了很长时间,所以我终于研究了这个,并给了你这个冗长的理由来解释为什么事情会这样。

规格

Section 11.9.4   The Strict Equals Operator ( === )

The production EqualityExpression : EqualityExpression === RelationalExpression
is evaluated as follows: 
- Let lref be the result of evaluating EqualityExpression.
- Let lval be GetValue(lref).
- Let rref be the result of evaluating RelationalExpression.
- Let rval be GetValue(rref).
- Return the result of performing the strict equality comparison 
  rval === lval. (See 11.9.6)

所以现在我们去 11.9.6

11.9.6   The Strict Equality Comparison Algorithm

The comparison x === y, where x and y are values, produces true or false. 
Such a comparison is performed as follows: 
- If Type(x) is different from Type(y), return false.
- If Type(x) is Undefined, return true.
- If Type(x) is Null, return true.
- If Type(x) is Number, then
...
- If Type(x) is String, then return true if x and y are exactly the 
  same sequence of characters (same length and same characters in 
  corresponding positions); otherwise, return false.

就是这样。应用于字符串的三等号运算符返回真,前提是参数是完全相同的字符串(相同的长度和对应位置的相同字符)。

===当我们尝试比较可能来自不同来源但我们知道最终将具有相同值的字符串时,这将起作用 - 这是我们代码中内联字符串的常见场景。例如,如果我们有一个名为 的变量connection_state,并且我们想知道它['connecting', 'connected', 'disconnecting', 'disconnected']现在处于以下哪种状态,我们可以直接使用===.

但还有更多。就在 11.9.4 之上,有一个简短的说明:

NOTE 4     
  Comparison of Strings uses a simple equality test on sequences of code 
  unit values. There is no attempt to use the more complex, semantically oriented
  definitions of character or string equality and collating order defined in the 
  Unicode specification. Therefore Strings values that are canonically equal
  according to the Unicode standard could test as unequal. In effect this 
  algorithm assumes that both Strings are already in normalized form.

唔。现在怎么办?外部获得的字符串可以而且很可能会是奇怪的 unicodey,我们的温柔===不会公正对待它们。进来localeCompare救援:

15.5.4.9   String.prototype.localeCompare (that)
    ...
    The actual return values are implementation-defined to permit implementers 
    to encode additional information in the value, but the function is required 
    to define a total ordering on all Strings and to return 0 when comparing
    Strings that are considered canonically equivalent by the Unicode standard. 

我们现在可以回家了。

tl;博士;

要比较 javascript 中的字符串,请使用localeCompare; 如果您知道字符串没有非 ASCII 组件,因为它们是例如内部程序常量,那么===也可以使用。

于 2013-02-07T18:06:20.243 回答
5

解释为什么问题中的方法不起作用:

let products = [
    { name: "laptop", price: 800 },
    { name: "phone", price:200},
    { name: "tv", price: 1200}
];
products.sort( (a, b) => {
    {let value= a.name - b.name; console.log(value); return value}
});

> 2 NaN

字符串之间的减法返回 NaN。

与@Alejadro 的回答相呼应,正确的做法是——

products.sort( (a,b) => a.name > b.name ? 1 : -1 )

于 2020-10-30T16:05:36.703 回答
4

在javascript中,我们使用.localCompare方法对字符串进行排序

对于打字稿

const data = ["jane", "mike", "salome", "ababus", "buisa", "dennis"];

const sort = (arr: string[], mode?: 'desc' | 'asc') => 
  !mode || mode === "asc"
    ? arr.sort((a, b) => a.localeCompare(b))
    : arr.sort((a, b) => b.localeCompare(a));


console.log(sort(data, 'desc'));// [ 'salome', 'mike', 'jane', 'dennis', 'buisa', 'ababus' ]
console.log(sort(data, 'asc')); // [ 'ababus', 'buisa', 'dennis', 'jane', 'mike', 'salome' ]


对于 JS

const data = ["jane", "mike", "salome", "ababus", "buisa", "dennis"];

/**
 * @param {string[]} arr
 * @param {"asc"|"desc"} mode
 */
const sort = (arr, mode = "asc") =>
  !mode || mode === "asc"
    ? arr.sort((a, b) => a.localeCompare(b))
    : arr.sort((a, b) => b.localeCompare(a));

console.log(sort(data, 'desc'));// [ 'salome', 'mike', 'jane', 'dennis', 'buisa', 'ababus' ]
console.log(sort(data, 'asc')); // [ 'ababus', 'buisa', 'dennis', 'jane', 'mike', 'salome' ]
于 2021-12-21T02:39:29.657 回答
2

应该有升序和降序功能

if (order === 'asc') {
  return a.localeCompare(b);
}
return b.localeCompare(a);
于 2021-06-24T21:45:13.350 回答
1
list.sort(function(item1, item2){
    return +(item1.attr > item2.attr) || +(item1.attr === item2.attr) - 1;
}) 

他们如何工作示例:

+('aaa'>'bbb')||+('aaa'==='bbb')-1
+(false)||+(false)-1
0||0-1
-1

+('bbb'>'aaa')||+('bbb'==='aaa')-1
+(true)||+(false)-1
1||0-1
1

+('aaa'>'aaa')||+('aaa'==='aaa')-1
+(false)||+(true)-1
0||1-1
0
于 2016-09-01T21:41:22.050 回答
0

在您最初问题的操作中,您正在执行以下操作:

item1.attr - item2.attr

因此,假设这些是数字(即 item1.attr = "1", item2.attr = "2"),只要您确保类型,您仍然可以使用“===”运算符(或其他严格的评估器)。以下应该有效:

return parseInt(item1.attr) - parseInt(item2.attr);

如果它们是 alphaNumeric,则使用 localCompare()。

于 2013-10-24T18:15:33.813 回答
0

直接使用 sort() 没有任何-<

const areas = ['hill', 'beach', 'desert', 'mountain']
console.log(areas.sort())

// To print in descending way
console.log(areas.sort().reverse())

于 2021-01-31T12:32:54.937 回答
0

如果您想控制语言环境(或大小写或重音),请使用Intl.collator

const collator = new Intl.Collator();
list.sort((a, b) => collator.compare(a.attr, b.attr));

您可以像这样构造整理器:

new Intl.Collator("en");
new Intl.Collator("en", {sensitivity: "case"});
...

请参阅上面的文档链接。

Note: unlike some other solutions, it handles null, undefined the JS way, i.e. moves them to the end.

于 2022-01-28T08:36:58.827 回答
-2
<!doctype html>
<html>
<body>
<p id = "myString">zyxtspqnmdba</p>
<p id = "orderedString"></p>
<script>
var myString = document.getElementById("myString").innerHTML;
orderString(myString);
function orderString(str) {
    var i = 0;
    var myArray = str.split("");
    while (i < str.length){
        var j = i + 1;
        while (j < str.length) {
            if (myArray[j] < myArray[i]){
                var temp = myArray[i];
                myArray[i] = myArray[j];
                myArray[j] = temp;
            }
            j++;
        }
        i++;
    }
    var newString = myArray.join("");
    document.getElementById("orderedString").innerHTML = newString;
}
</script>
</body>
</html>
于 2018-04-23T20:45:28.537 回答
-2
var str = ['v','a','da','c','k','l']
var b = str.join('').split('').sort().reverse().join('')
console.log(b)
于 2019-04-09T10:29:57.257 回答