【发布时间】:2012-02-18 07:08:39
【问题描述】:
我有一个字符串数组,需要在 JavaScript 中排序,但不区分大小写。如何执行此操作?
【问题讨论】:
标签: javascript sorting case-insensitive
我有一个字符串数组,需要在 JavaScript 中排序,但不区分大小写。如何执行此操作?
【问题讨论】:
标签: javascript sorting case-insensitive
在(几乎:)单行
["Foo", "bar"].sort(function (a, b) {
return a.toLowerCase().localeCompare(b.toLowerCase());
});
结果
[ 'bar', 'Foo' ]
虽然
["Foo", "bar"].sort();
结果
[ 'Foo', 'bar' ]
【讨论】:
return a.localeCompare(b, 'en', {'sensitivity': 'base'});
localeCompare 在某些情况下默认情况下不调用toLowerCase()。您可以在此处阅读有关要传递给它的参数的更多信息:developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
items.sort(new Intl.Collator('en').compare) 以获得更好的性能是有意义的。 (见MDN。)
是时候重新审视这个老问题了。
您不应使用依赖于toLowerCase 的解决方案。它们效率低下,并且在某些语言(例如土耳其语)中不起作用。喜欢这个:
['Foo', 'bar'].sort((a, b) => a.localeCompare(b, undefined, {sensitivity: 'base'}))
查看documentation 以了解浏览器兼容性以及所有有关sensitivity 选项的信息。
【讨论】:
['Foo', 'bar'].sort((a,b) => a.localeCompare(b)) 也有效
myArray.sort(
function(a, b) {
if (a.toLowerCase() < b.toLowerCase()) return -1;
if (a.toLowerCase() > b.toLowerCase()) return 1;
return 0;
}
);
编辑: 请注意,我最初写这篇文章是为了说明这项技术,而不是考虑到性能。另请参阅答案@Ivan Krechetov 以获得更紧凑的解决方案。
【讨论】:
toLowerCase两次;在变量中存储字符串的降低版本会更有效。
.toLowerCase()。例如,在对 10 个项目进行倒序排序时,调用了 45 次比较函数。 var i = 0; ["z","y","x","w","v","u","t","s","r","q"].sort(function (a, b) {++i; return a.toLowerCase().localeCompare(b.toLowerCase());}); console.log("Calls to Compare: " + i); // i === 45
arr.sort(function(a,b) {
a = a.toLowerCase();
b = b.toLowerCase();
if (a == b) return 0;
if (a > b) return 1;
return -1;
});
【讨论】:
return a === b ? 0 : a > b ? 1 : -1;
["111", "33"],我们可能希望它返回["111", "33"],因为在字符代码排序中1 在3 之前。但是,此答案中的函数将返回 ["33", "111"],因为数字 33 小于数字 111。
"33" > "111" === true 和 33 > 111 === false。它按预期工作。
您还可以使用新的Intl.Collator().compare,在对数组进行排序时,根据 MDN,它是 more efficient。缺点是旧浏览器不支持它。 MDN 声明 Safari 根本不支持它。需要验证它,因为它声明支持Intl.Collator。
当比较大量字符串时,比如对大数组进行排序,最好创建一个 Intl.Collator 对象,并使用它的 compare 属性提供的函数
["Foo", "bar"].sort(Intl.Collator().compare); //["bar", "Foo"]
【讨论】:
如果你想保证相同的顺序而不管输入数组中元素的顺序,这里有一个stable排序:
myArray.sort(function(a, b) {
/* Storing case insensitive comparison */
var comparison = a.toLowerCase().localeCompare(b.toLowerCase());
/* If strings are equal in case insensitive comparison */
if (comparison === 0) {
/* Return case sensitive comparison instead */
return a.localeCompare(b);
}
/* Otherwise return result */
return comparison;
});
【讨论】:
ES6 版本:
["Foo", "bar"].sort((a, b) => a.localeCompare(b, 'en', { sensitivity: 'base' }))
【讨论】:
用.toLowerCase() 规范化.sort() 中的情况。
【讨论】:
您也可以使用 Elvis 运算符:
arr = ['Bob', 'charley', 'fudge', 'Fudge', 'biscuit'];
arr.sort(function(s1, s2){
var l=s1.toLowerCase(), m=s2.toLowerCase();
return l===m?0:l>m?1:-1;
});
console.log(arr);
给予:
biscuit,Bob,charley,fudge,Fudge
localeCompare 方法可能没问题...
注意:Elvis 运算符是 if then else 的缩写形式“三元运算符”,通常带有赋值。
如果你看 ?: 侧面,它看起来像猫王......
即代替:
if (y) {
x = 1;
} else {
x = 2;
}
你可以使用:
x = y?1:2;
即当 y 为真时,返回 1(赋值给 x),否则返回 2(赋值给 x)。
【讨论】:
x = y ?: z 代替 x = y ? y : z。 Javascript 没有真正的 Elvis 运算符,但您可以以类似的方式使用 x = y || z。
其他答案假设数组包含字符串。我的方法更好,因为即使数组包含 null、undefined 或其他非字符串,它也能工作。
var notdefined;
var myarray = ['a', 'c', null, notdefined, 'nulk', 'BYE', 'nulm'];
myarray.sort(ignoreCase);
alert(JSON.stringify(myarray)); // show the result
function ignoreCase(a,b) {
return (''+a).toUpperCase() < (''+b).toUpperCase() ? -1 : 1;
}
null 将在“nulk”和“nulm”之间排序。但undefined 将始终排在最后。
【讨论】:
(''+notdefined) === "undefined" 所以它会排在“z”之前
Array.prototype.sort的定义:|因为关于(''+notdefined) === "undefined" 真的是 的部分是真的......这意味着如果你在排序函数中翻转 -1 和 1 以反转顺序, undefined 仍然排序到最后。在数组排序的上下文之外使用比较函数时也需要考虑这一点(就像我遇到这个问题时一样)。
Array.prototype.sort 的定义——更多的 cmets。首先,不需要(''+a) - ECMAScript 要求在将元素传递给 compareFn 之前对元素调用 toString()。其次,ignoreCase 在比较相等(包括大小写相等)字符串时返回1 的事实意味着如果存在重复值,规范没有定义结果(可能只是一些不必要的交换就可以了我认为正在发生)。
undefined 是一个特例,对于 any x xundefined 总是最后一个,是 sort 的 sort 实现的副产品。我试图将 (''+a) 更改为简单的 a,但它失败了。我得到TypeError: a.toUpperCase is not a function。显然toString 在调用 compareFn 之前没有被调用。undefined,compareFn 从不调用
为了支持已接受的答案,我想补充一点,下面的函数似乎改变了要排序的原始数组中的值,因此它不仅会对小写进行排序,而且大写的值也会更改为小写.这对我来说是个问题,因为即使我希望看到 Mary 紧挨着 Mary,我也不希望 Mary 的第一个值的大小写更改为小写。
myArray.sort(
function(a, b) {
if (a.toLowerCase() < b.toLowerCase()) return -1;
if (a.toLowerCase() > b.toLowerCase()) return 1;
return 0;
}
);
在我的实验中,接受答案中的以下函数排序正确,但不会更改值。
["Foo", "bar"].sort(function (a, b) {
return a.toLowerCase().localeCompare(b.toLowerCase());
});
【讨论】:
arr.sort(function(a,b) {
a = a.toLowerCase();
b = b.toLowerCase();
if( a == b) return 0;
if( a > b) return 1;
return -1;
});
在上面的函数中,如果我们只是比较小写两个值a和b,我们不会得到漂亮的结果。
例如,如果数组是 [A, a, B, b, c, C, D, d, e, E] 并且我们使用上面的函数,我们就得到了这个数组。它没有改变任何东西。
要得到结果是[A, a, B, b, C, c, D, d, E, e],我们应该在两个小写值相等时再次比较:
function caseInsensitiveComparator(valueA, valueB) {
var valueALowerCase = valueA.toLowerCase();
var valueBLowerCase = valueB.toLowerCase();
if (valueALowerCase < valueBLowerCase) {
return -1;
} else if (valueALowerCase > valueBLowerCase) {
return 1;
} else { //valueALowerCase === valueBLowerCase
if (valueA < valueB) {
return -1;
} else if (valueA > valueB) {
return 1;
} else {
return 0;
}
}
}
【讨论】:
如果您难以理解,这可能会有所帮助:
var array = ["sort", "Me", "alphabetically", "But", "Ignore", "case"];
console.log('Unordered array ---', array, '------------');
array.sort(function(a,b) {
a = a.toLowerCase();
b = b.toLowerCase();
console.log("Compare '" + a + "' and '" + b + "'");
if( a == b) {
console.log('Comparison result, 0 --- leave as is ');
return 0;
}
if( a > b) {
console.log('Comparison result, 1 --- move '+b+' to before '+a+' ');
return 1;
}
console.log('Comparison result, -1 --- move '+a+' to before '+b+' ');
return -1;
});
console.log('Ordered array ---', array, '------------');
// return logic
/***
If compareFunction(a, b) is less than 0, sort a to a lower index than b, i.e. a comes first.
If compareFunction(a, b) returns 0, leave a and b unchanged with respect to each other, but sorted with respect to all different elements. Note: the ECMAscript standard does not guarantee this behaviour, and thus not all browsers (e.g. Mozilla versions dating back to at least 2003) respect this.
If compareFunction(a, b) is greater than 0, sort b to a lower index than a.
***/
【讨论】:
我将最佳答案包装在一个 polyfill 中,这样我就可以在字符串数组上调用 .sortIgnoreCase()
// Array.sortIgnoreCase() polyfill
if (!Array.prototype.sortIgnoreCase) {
Array.prototype.sortIgnoreCase = function () {
return this.sort(function (a, b) {
return a.toLowerCase().localeCompare(b.toLowerCase());
});
};
}
【讨论】:
将您的字符串包装在/ /i 中。这是使用正则表达式忽略大小写的简单方法
【讨论】: