如何在 JavaScript 中对字符串进行排序
Posted
技术标签:
【中文标题】如何在 JavaScript 中对字符串进行排序【英文标题】:How to sort strings in JavaScript 【发布时间】:2010-09-08 05:55:49 【问题描述】:我有一个对象列表,我希望根据字符串类型的字段attr
进行排序。我尝试使用-
list.sort(function (a, b)
return a.attr - b.attr
)
但发现-
似乎不适用于 javascript 中的字符串。如何根据字符串类型的属性对对象列表进行排序?
【问题讨论】:
见JavaScript case insensitive string comparison
***.com/questions/2140627/…
对于一个快速的“国际化”解决方案(我猜只是部分地,因为这可能无法涵盖世界上所有的口音),您可能想简单地忽略口音,即删除它们。然后只做你的字符串比较,见Javascript : remove accents/diacritics in strings
***.com/questions/990904/…
有趣的是,杰夫·阿特伍德本人早在 2007 年就写过一篇关于这个常见问题的博文,请参阅 blog.codinghorror.com/sorting-for-humans-natural-sort-order
【参考方案1】:
根据您的示例使用String.prototype.localeCompare
:
list.sort(function (a, b)
return ('' + a.attr).localeCompare(b.attr);
)
我们强制 a.attr 为字符串以避免异常。 localeCompare
已受支持 since Internet Explorer 6 和 Firefox 1。您可能还会看到使用的以下代码不尊重语言环境:
if (item1.attr < item2.attr)
return -1;
if ( item1.attr > item2.attr)
return 1;
return 0;
【讨论】:
在有人像我一样草率犯下错误之前,这是本地e比较,而不是本地比较。 第一个解决方案将考虑“A”在“z”之后但在“Z”之前,因为它正在对字符 ASCII 值进行比较。localeCompare()
没有遇到这个问题,但不理解数字,所以你会得到 [ "1", "10", "2" ],就像大多数语言中的排序比较一样。如果您想对 UI 前端进行排序,请查看字母数字/自然排序算法 ***.com/questions/4340227/… 或 ***.com/questions/4321829/…
请注意,localeCompare()
仅在现代浏览器中受支持:IE11+ 在撰写本文时,请参阅developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
不,我的意思是表格的第一行,@Adrien - IE 支持 localeCompare()
退回许多版本,但直到版本 11 才支持指定区域设置。还要注意 Dead.Rabit 链接到的问题。
@Shog9 我的错,好像从 IE6 开始就支持它了!请参阅msdn.microsoft.com/en-us/library/ie/s4esdbwz(v=vs.94).aspx 上的(向下滚动/搜索到 localeCompare() 方法)。不过需要注意的一点是,在我们不使用语言环境和选项参数的旧实现中(在 IE11 之前使用的那个)使用的语言环境和排序顺序完全依赖于实现,换句话说:Firefox 、Safari、Chrome 和 IE 不会以相同的顺序对字符串进行排序。见code.google.com/p/v8/issues/detail?id=459【参考方案2】:
更新的答案(2014 年 10 月)
我对这个字符串自然排序顺序感到非常恼火,所以我花了一些时间来调查这个问题。我希望这会有所帮助。
长话短说
localeCompare()
字符支持很糟糕,只需使用它。
正如Shog9
所指出的,您的问题的答案是:
return item1.attr.localeCompare(item2.attr);
在所有自定义 javascript“自然字符串排序顺序”实现中发现的错误
那里有很多自定义实现,试图更精确地进行字符串比较,称为“自然字符串排序顺序”
在“玩”这些实现时,我总是注意到一些奇怪的“自然排序顺序”选择,或者更确切地说是错误(最好的情况下是遗漏)。
通常情况下,特殊字符(空格、破折号、与号、括号等)不会被正确处理。
然后您会发现它们在不同的地方混在一起,通常可能是:
有些会在大写“Z”和小写“a”之间 有些会在“9”和大写“A”之间 有些会在小写“z”之后当人们期望特殊字符全部“组合”在一个地方时,可能除了空格特殊字符(它始终是第一个字符)。也就是说,要么全部在数字之前,要么全部在数字和字母之间(小写和大写一个接一个地“在一起”),或者全部在字母之后。
我的结论是,当我开始添加几乎不常见的字符(即带有变音符号或破折号、感叹号等字符的字符)时,它们都无法提供一致的顺序。
自定义实现研究:
Natural Compare Lite
https://github.com/litejs/natural-compare-lite :无法一致排序 https://github.com/litejs/natural-compare-lite/issues/1 和 http://jsbin.com/bevututodavi/1/edit?js,console ,基本拉丁字符排序 http://jsbin.com/bevututodavi/5/edit?js,console
Natural Sort
https://github.com/javve/natural-sort :始终无法排序,请参阅问题 https://github.com/javve/natural-sort/issues/7 并查看基本拉丁字符排序 http://jsbin.com/cipimosedoqe/3/edit?js,console
Javascript Natural Sort
https://github.com/overset/javascript-natural-sort :自 2012 年 2 月以来似乎被忽视了,始终无法排序,请参阅问题 https://github.com/overset/javascript-natural-sort/issues/16
Alphanum
http://www.davekoelle.com/files/alphanum.js , 排序失败,见http://jsbin.com/tuminoxifuyo/1/edit?js,console
浏览器的原生“自然字符串排序”通过localeCompare()
实现
localeCompare()
最旧的实现(没有语言环境和选项参数)受 IE6+ 支持,请参阅http://msdn.microsoft.com/en-us/library/ie/s4esdbwz(v=vs.94).aspx(向下滚动到 localeCompare() 方法)。
内置的localeCompare()
方法在排序方面做得更好,甚至是国际和特殊字符。
使用localeCompare()
方法的唯一问题是"the locale and sort order used are entirely implementation dependent". In other words, when using localeCompare such as stringOne.localeCompare(stringTwo): Firefox, Safari, Chrome & IE have a different sort order for Strings.
浏览器原生实现研究:
http://jsbin.com/beboroyifomu/1/edit?js,console - 与 localeCompare() 的基本拉丁字符比较 http://jsbin.com/viyucavudela/2/ - 与 localeCompare() 进行基本拉丁字符比较以在 IE8 上进行测试 http://jsbin.com/beboroyifomu/2/edit?js,console - 字符串比较中的基本拉丁字符:字符串与单独字符时的一致性检查 https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/localeCompare - IE11+ 支持新的语言环境和选项参数“字符串自然排序顺序”的难点
实现一个可靠的算法(意思是:一致但也涵盖广泛的字符)是一项非常艰巨的任务。 UTF8 包含 more than 2000 characters 和 covers more than 120 scripts (languages)。 最后,这个任务有一些规范,称为“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);
延伸阅读:
https://softwareengineering.stackexchange.com/questions/257286/is-there-any-language-agnostic-specification-for-string-natural-sorting-order How do you do string comparison in JavaScript? Javascript : natural sort of alphanumerical strings Sort Array of numeric & alphabetical elements (Natural Sort) Sort mixed alpha/numeric array https://web.archive.org/web/20130929122019/http://my.opera.com/GreyWyvern/blog/show.dml/1671288 https://web.archive.org/web/20131005224909/http://www.davekoelle.com/alphanum.html http://snipplr.com/view/36012/javascript-natural-sort/ http://blog.codinghorror.com/sorting-for-humans-natural-sort-order/感谢 Shog9 的精彩回答,让我朝着我相信的“正确”方向前进
【讨论】:
【参考方案3】:答案(在现代 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;
【讨论】:
正如我对使用此技巧的 earlier answer 所评论的那样,通过解释它们的工作原理,可以使纯代码答案更加有用。 添加说明 你能评论一下这比 localeCompare 好还是坏? @RanLottemlocaleCompare
和标准比较产生不同的结果。你期待哪个? ["A", "b", "C", "d"].sort((a, b) => a.localeCompare(b))
按不区分大小写的字母顺序排序,而 ["A", "b", "C", "d"].sort((a, b) => (a > b) - (a < b))
按代码点顺序排序
这比 localeCompare 更好,因为 localeCompare 将为不相等的字符串返回 0。具体示例:(至少)有两个不同的“Ö”符号看起来相同,并且 localeCompare 表示它们相同,但它们失败 === (即使大写)。所以你漂亮的 UI 代码可能会做一些涉及排序和分组的事情,并且“Ö”与“Ö”相同,但是使用 Map 的后端逻辑将决定这两个 Ö 是不同的,所以结果很糟糕。 【参考方案4】:
因为字符串可以直接在 javascript 中进行比较,所以这样就可以了
list.sort(function (a, b)
return a.attr > b.attr ? 1: -1;
)
排序函数中的减法仅在需要非字母(数字)排序时使用,当然它不适用于字符串
【讨论】:
【参考方案5】:您应该在此处使用 > 或
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;
);
【讨论】:
附带说明,这不会处理字符串与数字的比较。例如:'Z' 9(也是假的??),'Z' == 9(也是假的!!)。 JavaScript 中的愚蠢 NaN...【参考方案6】:嵌套三元箭头函数
(a,b) => (a < b ? -1 : a > b ? 1 : 0)
【讨论】:
【参考方案7】:我为这个问题困扰了很久,所以我终于研究了这个,并给你这个冗长的理由来解释为什么事情会这样。
来自spec:
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.
就是这样。 如果参数是完全相同的字符串(相同的长度和对应位置的相同字符),则应用于字符串的三重等号运算符返回 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.
嗯。现在怎么办?外部获得的字符串可能而且很可能会是奇怪的 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;dr;
要在 javascript 中比较字符串,请使用 localeCompare
;如果您知道字符串没有非 ASCII 组件,因为它们是例如内部程序常量,那么 ===
也可以工作。
【讨论】:
【参考方案8】:解释为什么问题中的方法不起作用:
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 )
【讨论】:
【参考方案9】:应该有升序和降序功能
if (order === 'asc')
return a.localeCompare(b);
return b.localeCompare(a);
【讨论】:
【参考方案10】: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
【讨论】:
只有代码的答案可以通过解释它们的工作原理来变得更有用。【参考方案11】:打字稿排序方法修饰符,使用自定义函数以升序或降序返回排序后的字符串
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' ]
【讨论】:
【参考方案12】:在您最初问题的操作中,您正在执行以下操作:
item1.attr - item2.attr
因此,假设这些是数字(即 item1.attr = "1", item2.attr = "2"),只要您确保类型,您仍然可以使用“===”运算符(或其他严格的评估器)。以下应该有效:
return parseInt(item1.attr) - parseInt(item2.attr);
如果它们是 alphaNumeric,则使用 localCompare()。
【讨论】:
【参考方案13】:直接使用 sort() 没有任何 -
或 <
const areas = ['hill', 'beach', 'desert', 'mountain']
console.log(areas.sort())
// To print in descending way
console.log(areas.sort().reverse())
【讨论】:
【参考方案14】:<!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>
【讨论】:
请在您的答案中添加一些关于这将如何解决问题的信息。不欢迎纯代码答案。谢谢。 在这里您想对字符串中的字符进行排序,这不是所要求的。您可以简单地使用“Array.sort”来实现这种排序,例如str.split("").sort().join("")【参考方案15】:var str = ['v','a','da','c','k','l']
var b = str.join('').split('').sort().reverse().join('')
console.log(b)
【讨论】:
虽然此代码可能会解决问题,including an explanation 关于如何以及为什么解决问题将真正有助于提高您的帖子质量,并可能导致更多的赞成票。请记住,您正在为将来的读者回答问题,而不仅仅是现在提问的人。请edit您的答案添加解释,并说明适用的限制和假设。以上是关于如何在 JavaScript 中对字符串进行排序的主要内容,如果未能解决你的问题,请参考以下文章