我有一个对象列表,希望按照类型为字符串的字段attr
进行排序。我尝试使用-
。
list.sort(function (a, b) {
return a.attr - b.attr
})
但是我发现在 JavaScript 中,-
似乎不能用于字符串。那么如何根据一个字符串类型的属性对对象列表进行排序呢?
但我发现JavaScript中-
不能用于字符串。如何基于字符串类型的属性对对象列表进行排序?
我有一个对象列表,希望按照类型为字符串的字段attr
进行排序。我尝试使用-
。
list.sort(function (a, b) {
return a.attr - b.attr
})
但是我发现在 JavaScript 中,-
似乎不能用于字符串。那么如何根据一个字符串类型的属性对对象列表进行排序呢?
但我发现JavaScript中-
不能用于字符串。如何基于字符串类型的属性对对象列表进行排序?
按照您的示例使用String.prototype.localeCompare
:
list.sort(function (a, b) {
return ('' + a.attr).localeCompare(b.attr);
})
if (item1.attr < item2.attr)
return -1;
if ( item1.attr > item2.attr)
return 1;
return 0;
localeCompare()
不会遇到这个问题,但是它不能识别数字,所以你得到的结果将是["1", "10", "2"],这与大多数语言中的排序比较相同。如果你想要在UI前端进行排序,请查看alphanum/natural排序算法https://dev59.com/22855IYBdhLWcg3wcz1h或https://dev59.com/8FLTa4cB1Zd3GeqPZE32。 - Dead.RabitlocaleCompare()
仅受现代浏览器支持:在撰写本文时,仅支持IE11+,请参见https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/localeCompare。 - AdrianolocaleCompare()
,但直到11版才支持*指定区域设置(locale)*。还要注意Dead.Rabit链接的那些问题。 - Shog9我对这个字符串的自然排序顺序感到非常恼火,所以花了很多时间来调查这个问题。
localeCompare()
的字符支持非常强大,只需使用它即可。
正如Shog9所指出的,对于你的问题的答案是:
return item1.attr.localeCompare(item2.attr);
有很多自定义实现尝试更精确地进行字符串比较,称为“自然字符串排序顺序”。
当使用这些实现时,我总是注意到一些奇怪的“自然排序顺序”选择,或者说是错误(或者在最好的情况下是遗漏)。
通常,特殊字符(空格、破折号、和号、括号等)没有被正确处理。
你会发现它们混在不同的位置出现,通常可能是:
当人们期望特殊字符都被“分组”在一起的时候,除了空格特殊字符(它通常是第一个字符)。也就是说,要么全部在数字之前,要么全部在数字和字母之间(小写字母和大写字母“连在一起”),要么全部在字母之后。
我的结论是,当我开始添加一些不太常见的字符(例如带有变音符号的字符或破折号、感叹号等字符)时,它们都无法提供一致的顺序。localeCompare()
localeCompare()最早的实现(不包括locales和options参数)支持Internet Explorer 6及更高版本,请参见Legacy Microsoft Edge开发者文档(向下滚动至localeCompare()方法)。
内置的localeCompare()
方法在排序方面做得更好,甚至可以处理国际和特殊字符。
使用localeCompare()
方法的唯一问题是{{link4:“所使用的区域设置和排序顺序完全取决于实现”。换句话说,当使用localeCompare比如stringOne.localeCompare(stringTwo)时:Firefox、Safari、Chrome和Internet Explorer对字符串有不同的排序顺序。}}
关于浏览器原生实现的研究:
实现一个稳定的算法(即:一致性且涵盖广泛的字符范围)是一项非常艰巨的任务。UTF-8包含超过2000个字符,并且涵盖了120多种文字(语言)。
最后,对于这个任务有一些规范,它被称为“Unicode排序算法”。您可以在我发布的这个问题上找到更多信息,是否有一种与语言无关的“字符串自然排序顺序”规范?
return item1.attr.localeCompare(item2.attr);
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) - (y < x)
-> 1 - 0
-> 1
(x > y) - (y < x)
-> 0 - 0
-> 0
(x > y) - (y < x)
-> 0 - 1
-> -1
(替代方案)
+(x > y) || -(x < y)
-> 1 || 0
-> 1
+(x > y) || -(x < y)
-> 0 || 0
-> 0
+(x > y) || -(x < y)
-> 0 || -1
-> -1
因此,这些逻辑与典型的排序比较函数等效。
if (x == y) {
return 0;
}
return x > y ? 1 : -1;
localeCompare
和标准比较产生不同的结果。你希望哪一个?["A", "b", "C", "d"].sort((a, b) => a.localeCompare(b))
按字母顺序(不区分大小写)排序,而 ["A", "b", "C", "d"].sort((a, b) => (a > b) - (a < b))
按 Unicode 码点顺序排序。 - mpyw由于在JavaScript中可以直接比较字符串,因此这样做就可以了:
list.sort(function (a, b) {
return a.attr < b.attr ? -1: 1;
})
这比使用的方法稍微更有效率一些。
return a.attr > b.attr ? 1: -1;
因为在具有相同属性的元素的情况下(a.attr == b.attr),排序函数会无故地交换两者位置。 var so1 = function (a, b) { return a.atr > b.atr ? 1: -1; };
var so2 = function (a, b) { return a.atr < b.atr ? -1: 1; }; // Better
var m1 = [ { atr: 40, s: "FIRST" }, { atr: 100, s: "LAST" }, { atr: 40, s: "SECOND" } ].sort (so1);
var m2 = [ { atr: 40, s: "FIRST" }, { atr: 100, s: "LAST" }, { atr: 40, s: "SECOND" } ].sort (so2);
// m1 sorted but ...: 40 SECOND 40 FIRST 100 LAST
// m2 more efficient: 40 FIRST 40 SECOND 100 LAST
您应该在此处使用>或<和==。因此,解决方案将是:
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;
});
嵌套三元箭头函数
(a,b) => (a < b ? -1 : a > b ? 1 : 0)
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' ]
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)
我一直为此感到困扰,所以最终我研究了这个问题,并给出了这个冗长的解释,说明事情为什么会是这样。
从规范中可以看到:
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 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.
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.
嗯,现在怎么办?外部获得的字符串可能会很奇怪,其中包含许多Unicode字符,而我们温柔的===
操作符可能无法处理它们。这时就需要用到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.
如果您想控制区域设置(或大小写或重音符号),那么请使用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"});
...
null, undefined
,即将它们移到最后。