如何在JavaScript中对字符串进行排序

air*_*tyh 314 javascript string

我有一个我希望根据attr字符串类型字段排序的对象列表.我试过用-

list.sort(function (a, b) {
    return a.attr - b.attr
})
Run Code Online (Sandbox Code Playgroud)

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

Sho*_*og9 559

使用String.prototype.localeCompare每个您的示例:

list.sort(function (a, b) {
    return ('' + a.attr).localeCompare(b.attr);
})
Run Code Online (Sandbox Code Playgroud)

我们强制a.attr为字符串以避免异常.自Internet Explorer 6和Firefox 1 以来localeCompare一直受支持.您还可能会看到以下使用的代码不符合区域设置:

if (item1.attr < item2.attr)
  return -1;
if ( item1.attr > item2.attr)
  return 1;
return 0;
Run Code Online (Sandbox Code Playgroud)

  • 在任何人犯下与我一样的仓促错误之前,它是本地*e*比较,而不是localCompare. (65认同)
  • 第一个解决方案将在"z"之后但在"Z"之前考虑"A",因为它正在对字符ASCII值进行比较.`localeCompare()`不会遇到这个问题,但是不理解数字,所以你会得到["1","10","2"]和大多数语言中的排序比较一样.如果您想要对UI前端进行排序,请查看alphanum /自然排序算法http://stackoverflow.com/questions/4340227/sort-mixed-alpha-numeric-array或http://stackoverflow.com/questions/ 4321829 /字母数字-分拣中的java脚本 (12认同)
  • 不,我的意思是表的第一行,@ Adrien - IE支持`localeCompare()`返回许多版本,但不支持*指定语言环境*直到版本11.还要注意Dead.Rabit链接的问题. (3认同)
  • 请注意,`localeCompare()`仅在现代浏览器中受支持:IE11 +在撰写本文时,请参阅https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/localeCompare (2认同)
  • @ Shog9我的不好,似乎它是IE6以来的支持!请参阅http://msdn.microsoft.com/en-us/library/ie/s4esdbwz(v=vs.94).aspx上的(向下滚动/搜索到localeCompare()方法).有一点需要注意,在旧的实现中,我们不使用locales和options参数(在IE11之前使用的参数)*使用的语言环境和排序顺序完全取决于实现*,换句话说:Firefox,Safari,Chrome& IE不会以相同的顺序对字符串进行排序.请参阅https://code.google.com/p/v8/issues/detail?id=459 (2认同)

Adr*_* Be 151

更新的答案(2014年10月)

我真的很烦恼这个字符串自然排序顺序,所以我花了很长时间来研究这个问题.我希望这有帮助.

长话短说

localeCompare()角色支持是坏蛋,只需使用它.正如所指出的Shog9,你的问题的答案是:

return item1.attr.localeCompare(item2.attr);
Run Code Online (Sandbox Code Playgroud)

在所有自定义javascript"自然字符串排序顺序"实现中找到的错误

有很多自定义实现,尝试进行字符串比较更准确地称为"自然字符串排序顺序"

当"玩"这些实现时,我总是注意到一些奇怪的"自然排序顺序"选择,或者说错误(或者在最好的情况下的遗漏).

通常,不能正确处理特殊字符(空格,短划线,和号,括号等).

然后你会发现它们出现在不同的地方,通常可能是:

  • 一些将在大写的'Z'和小写的'a'之间
  • 一些将介于'9'和大写'A'之间
  • 一些将在小写'z'之后

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

我的结论是,它们都未能提供一致的订单时,我开始增加几乎没有不寻常的字符(即用变音符号或charcters如破折号,感叹号等字符).

研究自定义实现:

浏览器的本机"自然字符串排序顺序"实现 localeCompare()

localeCompare()IE6 +支持最老的实现(没有locales和options参数),请参阅http://msdn.microsoft.com/en-us/library/ie/s4esdbwz (v=vs.94) .aspx(向下滚动到localeCompare( ) 方法).内置localeCompare()方法在排序方面做得更好,甚至包括国际和特殊字符.使用该localeCompare()方法的唯一问题是"使用的语言环境和排序顺序完全依赖于实现".换句话说,当使用localeCompare如stringOne.localeCompare(stringTwo)时: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);
Run Code Online (Sandbox Code Playgroud)

进一步阅读:

感谢Shog9的好回答,这让我相信"正确"的方向


mpy*_*pyw 29

答案(在现代ECMAScript中)

list.sort((a, b) => (a.attr > b.attr) - (a.attr < b.attr))
Run Code Online (Sandbox Code Playgroud)

要么

list.sort((a, b) => +(a.attr > b.attr) || -(a.attr < b.attr))
Run Code Online (Sandbox Code Playgroud)

描述

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

  • 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;
Run Code Online (Sandbox Code Playgroud)

  • 正如我对使用此技巧的 [早期答案](/sf/answers/2749691171/) 的评论一样,通过解释它们的工作原理,可以使纯代码答案更有用。 (2认同)
  • @RanLottem`localeCompare`和标准比较产生不同的结果.您对此有何看法?`["A","b","C","d"].sort((a,b)=> a.localeCompare(b))`用不区分大小写的字母顺序排序,而`["A", "b","C","d"].排序((a,b)=>(a> b) - (a <b))`在码点顺序中 (2认同)
  • 这比 localeCompare *更好*,因为 localeCompare 对于不相等的字符串将返回 0。具体示例:(至少)有两个不同的“Ö”符号看起来相同,localeCompare 说它们是相同的,但它们失败 === (即使是大写的)。因此,您漂亮的 UI 代码可能会执行一些涉及排序和分组的操作,并且“Ö”与“Ö”相同,但使用 Map 的后端逻辑将决定这两个 Ö 不同,因此结果会很糟糕。 (2认同)

Ale*_*der 14

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

list.sort(function (a, b) {
    return a.attr > b.attr ? 1: -1;
})
Run Code Online (Sandbox Code Playgroud)

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


air*_*tyh 11

你应该在这里使用>或<和==.所以解决方案是:

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;
});
Run Code Online (Sandbox Code Playgroud)


tas*_*ash 9

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

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
Run Code Online (Sandbox Code Playgroud)

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

响应Alejadro 的答案,正确的方法是:

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


Fel*_*nda 9

TypeScript 排序方法修饰符使用自定义函数返回按升序或降序排序的字符串:

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

const sortStringArray = (stringArray: string[], mode?: 'desc' | 'asc') => {
  if (!mode || mode === 'asc') {
    return stringArray.sort((a, b) => a.localeCompare(b))
  }
  return stringArray.sort((a, b) => b.localeCompare(a))
}

console.log(sortStringArray(data, 'desc'));// [ 'salome', 'mike', 'jane', 'dennis', 'buisa', 'ababus' ]
console.log(sortStringArray(data, 'asc')); // [ 'ababus', 'buisa', 'dennis', 'jane', 'mike', 'salome' ]
Run Code Online (Sandbox Code Playgroud)


Man*_*nav 6

我长期以来一直对此感到烦恼,所以我终于研究了这个并给你这个长期的理由,为什么事情就像他们一样.

规格:

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)
Run Code Online (Sandbox Code Playgroud)

现在我们转到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.
Run Code Online (Sandbox Code Playgroud)

而已.如果参数完全相同的字符串(相应位置的相同长度和相同字符),则应用于字符串的三重等于运算符将返回true.

因此===,当我们尝试比较可能来自不同来源的字符串,但我们知道它们最终将具有相同的值时,这种情况会起作用 - 这是我们代码中内联字符串的常见情况.例如,如果我们有一个名为的变量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.
Run Code Online (Sandbox Code Playgroud)

嗯.现在怎么办?外部获得的字符串可能,而且很可能会是奇怪的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. 
Run Code Online (Sandbox Code Playgroud)

我们现在可以回家了.

TL;博士;

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


xme*_*eko 6

如果您想控制区域设置(或大小写或重音),请使用Intl.collator

const collator = new Intl.Collator();
list.sort((a, b) => collator.compare(a.attr, b.attr));
Run Code Online (Sandbox Code Playgroud)

您可以构建一个整理器,例如:

new Intl.Collator("en");
new Intl.Collator("en", {sensitivity: "case"});
...
Run Code Online (Sandbox Code Playgroud)

请参阅上面的链接以获取文档。

注意:与其他一些解决方案不同,它以null, undefinedJavaScript 方式处理,即将它们移动到末尾。


gec*_*kos 5

嵌套三元箭头功能

(a,b) => (a < b ? -1 : a > b ? 1 : 0)
Run Code Online (Sandbox Code Playgroud)


dea*_*fry 5

应该有升序和降序功能

if (order === 'asc') {
  return a.localeCompare(b);
}
return b.localeCompare(a);
Run Code Online (Sandbox Code Playgroud)


归档时间:

查看次数:

308531 次

最近记录:

5 年,10 月 前