如何在JavaScript中执行不区分大小写的排序?


Answers:


404

在(几乎:)单线

["Foo", "bar"].sort(function (a, b) {
    return a.toLowerCase().localeCompare(b.toLowerCase());
});

导致

[ 'bar', 'Foo' ]

["Foo", "bar"].sort();

结果是

[ 'Foo', 'bar' ]

9
请注意,并非所有平台/浏览器都支持localeCompare的高级选项。我知道在此示例中未使用它们,只是为了添加清楚起见。有关更多信息,请参见MDN
Ayame __,2014年

97
如果要使用localeCompare(),则可以使用不区分大小写的功能,例如:return a.localeCompare(b, 'en', {'sensitivity': 'base'});
Michael Dyck 2014年

2
+1不打电话toLowerCase()的时候localeCompare已经这样做,默认情况下在某些情况下。:你可以阅读更多有关参数传递给在这里developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/...
Milimetric

3
@Milimetric符合参考页面,某些浏览器(例如IE <11或Safari)不支持该功能。这里提到的解决方案非常好,但对于某些浏览器仍然需要反向移植/ polyfill。
3k- 2015年

2
如果阵列很大,则可以使用它来items.sort(new Intl.Collator('en').compare)获得更好的性能。(请参阅MDN。)
valtlai

60
myArray.sort(
  function(a, b) {
    if (a.toLowerCase() < b.toLowerCase()) return -1;
    if (a.toLowerCase() > b.toLowerCase()) return 1;
    return 0;
  }
);

编辑: 请注意,我最初是为了说明该技术而写的,而不是考虑性能。另请参阅答案@Ivan Krechetov,以获取更紧凑的解决方案。


3
toLowerCase每个字符串可以调用两次;将字符串的降低版本存储在变量中会更有效。
雅各布

真的,谢谢。我写这篇文章时的目的是清晰,而不是性能。我想我应该注意这一点。
ron tornambe 2013年

1
@Jacob公平地说,被接受的答案具有相同的基本问题:它可能会.toLowerCase()为数组中的每个项目多次调用。例如,当以相反顺序对10个项目进行排序时,有45个调用compare函数。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
没必要,2016年

47

现在该重新讨论这个老问题了。

您不应该使用依赖的解决方案toLowerCase。它们效率低下,根本无法在某些语言中使用(例如土耳其语)。喜欢这个:

['Foo', 'bar'].sort((a, b) => a.localeCompare(b, undefined, {sensitivity: 'base'}))

查看文档以了解浏览器兼容性,以及有关该sensitivity选项的所有信息。


1
请注意,并非所有的JavaScript引擎都支持此功能。
LubošTurek的

26
arr.sort(function(a,b) {
    a = a.toLowerCase();
    b = b.toLowerCase();
    if (a == b) return 0;
    if (a > b) return 1;
    return -1;
});

1
return a === b ? 0 : a > b ? 1 : -1;
Devin G Rhode

这可能会行不通的预期,对于表示数字的字符串。算术运算符将使用数字而不是字符串的语义。例如,如果我们有["111", "33"],我们可能希望它返回,["111", "33"]因为在字符代码排序中1在3之前。但是,此答案中的函数将返回,["33", "111"]因为number 33小于number 111
奥斯汀·戴维斯

@AustinDavis "33" > "111" === true33 > 111 === false。它按预期工作。
Niet the Dark Absol

12

您还可以使用Intl.Collator().compare每个MDN 的new ,对数组进行排序时效率更高。缺点是旧版浏览器不支持它。MDN指出Safari完全不支持它。需要验证它,因为它表明Intl.Collator受支持。

比较大量字符串时,例如在对大型数组进行排序时,最好创建一个Intl.Collat​​or对象并使用其compare属性提供的功能。

["Foo", "bar"].sort(Intl.Collator().compare); //["bar", "Foo"]

11

如果您想保证相同的顺序而不管输入数组中元素的顺序如何,这里是一种稳定的排序:

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;
});

5

规范化的情况下.sort().toLowerCase()


4

您还可以使用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 (y) {
  x = 1;
} else {
  x = 2;
}

您可以使用:

x = y?1:2;

即,当y为true时,则返回1(分配给x),否则返回2(分配给x)。


5
要学究一点,这不是猫王操作员。这只是基本的三元运算符。真正的Elvis运算符是null运算符,例如x = y ? y : z,您可以这样做x = y ?: z。Javascript没有实际的Elvis运算符,但是您可以x = y || z以类似的方式使用。
查尔斯·伍德

3

其他答案假定该数组包含字符串。我的方法更好,因为即使数组包含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”之前排序
-MattW

猜猜我应该检查一下Array.prototype.sort:| 的定义 因为有关的部分(''+notdefined) === "undefined" 确实是正确的……这意味着,如果在sort函数中翻转-1和1以颠倒顺序,则undefined仍会排序到最后。当在数组排序的上下文之外使用比较函数时,也需要考虑它(就像我遇到这个问题时一样)。
MattW

现在考虑了这个Array.prototype.sort定义-再加上一些评论。首先,不需要(''+a)-将ECMAScript要求toString()在将元素传递到compareFn之前对其进行调用。其次,在比较相等(包括大小写相等)字符串时ignoreCase返回的事实1意味着,如果有重复的值,则规范不会定义结果(我认为,只要发生一些不必要的交换,就可以了)。
MattW

@MattW,在我看来这undefined是一个特例,对于任何x x <undefined和x> undefined都是false。那undefined永远是最后,是sort的sort实现的副产品。我试图将(''+ a)更改为简单的a,但是失败了。我明白了TypeError: a.toUpperCase is not a function。显然toString不能在调用compareFn调用。
John Henckel

1
嗯,好的,这很合理。对于undefinedcompareFn 从未被称为
John Henckel


1

为了支持已接受的答案,我想补充一点,下面的函数似乎改变了要排序的原始数组中的值,这样不仅可以对小写字母进行排序,还可以将大写字母的值更改为小写字母。这对我来说是个问题,因为即使我希望看到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());
});

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.
***/

http://jsfiddle.net/ianjamieson/wmxn2ram/1/


0
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;
        }
    }
}

-1

我将顶部答案包装在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());
        });
    };
}

请永远不要这样做。仅修改您拥有的东西的原型。这也不是polyfill,因为ECMAScript规范中没有这种Array方法。
Joe Maffei

-2

将琴弦包起来/ /i。这是使用正则表达式忽略大小写的简单方法


问题是关于排序,而不是匹配。
user4642212
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.