【问题标题】:How to perform case-insensitive sorting array of string in JavaScript?如何在 JavaScript 中执行不区分大小写的字符串排序数组?
【发布时间】:2012-02-18 07:08:39
【问题描述】:

我有一个字符串数组,需要在 JavaScript 中排序,但不区分大小写。如何执行此操作?

【问题讨论】:

    标签: javascript sorting case-insensitive


    【解决方案1】:

    在(几乎:)单行

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

    结果

    [ 'bar', 'Foo' ]
    

    虽然

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

    结果

    [ 'Foo', 'bar' ]
    

    【讨论】:

    • 请注意,并非所有平台/浏览器都支持 localeCompare 的高级选项。我知道他们没有在这个例子中使用,只是为了清楚起见而添加。 See MDN for more info
    • 如果你要涉及 localeCompare(),你可以使用 its 来区分大小写,例如:return a.localeCompare(b, 'en', {'sensitivity': 'base'});
    • +1 表示当localeCompare 在某些情况下默认情况下不调用toLowerCase()。您可以在此处阅读有关要传递给它的参数的更多信息:developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
    • @Milimetric 与引用的页面一致,某些浏览器不支持该功能(例如 IE
    • 如果你有一个大数组,使用items.sort(new Intl.Collator('en').compare) 以获得更好的性能是有意义的。 (见MDN。)
    【解决方案2】:

    是时候重新审视这个老问题了。

    您不应使用依赖于toLowerCase 的解决方案。它们效率低下,并且在某些语言(例如土耳其语)中不起作用。喜欢这个:

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

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

    【讨论】:

    • 请注意,并非所有 javascript 引擎都支持此功能。
    • 似乎所有浏览器现在都支持localCompare,除了一些移动浏览器不支持2个可选参数:developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
    • 看起来['Foo', 'bar'].sort((a,b) => a.localeCompare(b)) 也有效
    • @Ollie Williams 没有语言环境和选项参数,使用的语言环境和排序顺序完全取决于实现
    【解决方案3】:
    myArray.sort(
      function(a, b) {
        if (a.toLowerCase() < b.toLowerCase()) return -1;
        if (a.toLowerCase() > b.toLowerCase()) return 1;
        return 0;
      }
    );
    

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

    【讨论】:

    • 这可以在每个字符串上调用toLowerCase两次;在变量中存储字符串的降低版本会更有效。
    • 真的,谢谢。我写这篇文章时考虑清楚,而不是表现。我想我应该注意这一点。
    • @Jacob 公平地说,接受的答案具有相同的基本问题:它可能会为数组中的每个项目多次调用.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
    【解决方案4】:
    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 &gt; b ? 1 : -1;
    • 这对于表示数字的字符串可能按预期工作。算术运算符将使用数字的语义而不是字符串。例如。如果我们有["111", "33"],我们可能希望它返回["111", "33"],因为在字符代码排序中1 在3 之前。但是,此答案中的函数将返回 ["33", "111"],因为数字 33 小于数字 111
    • @AustinDavis "33" &gt; "111" === true33 &gt; 111 === false。它按预期工作。
    【解决方案5】:

    您还可以使用新的Intl.Collator().compare,在对数组进行排序时,根据 MDN,它是 more efficient。缺点是旧浏览器不支持它。 MDN 声明 Safari 根本不支持它。需要验证它,因为它声明支持Intl.Collator

    当比较大量字符串时,比如对大数组进行排序,最好创建一个 Intl.Collat​​or 对象,并使用它的 compare 属性提供的函数

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

    【讨论】:

      【解决方案6】:

      如果你想保证相同的顺序而不管输入数组中元素的顺序,这里有一个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;
      });
      

      【讨论】:

        【解决方案7】:

        ES6 版本:

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

        来源:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/localeCompare

        【讨论】:

          【解决方案8】:

          .toLowerCase() 规范化.sort() 中的情况。

          【讨论】:

            【解决方案9】:

            您也可以使用 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)。

            【讨论】:

            • 为了迂腐,这不是 Elvis 运算符。这只是一个基本的三元运算符。真正的 Elvis 运算符是空合并的,例如,您可以使用 x = y ?: z 代替 x = y ? y : z。 Javascript 没有真正的 Elvis 运算符,但您可以以类似的方式使用 x = y || z
            【解决方案10】:

            其他答案假设数组包含字符串。我的方法更好,因为即使数组包含 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 的事实意味着如果存在重复值,规范没有定义结果(可能只是一些不必要的交换就可以了我认为正在发生)。
            • @MattW,在我看来,undefined 是一个特例,对于 any x xundefined both false乙>。 undefined 总是最后一个,是 sort 的 sort 实现的副产品。我试图将 (''+a) 更改为简单的 a,但它失败了。我得到TypeError: a.toUpperCase is not a function。显然toString 在调用 compareFn 之前没有被调用。
            • 啊,好吧,这很有道理。对于undefined,compareFn 从不调用
            【解决方案11】:

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

            【讨论】:

            • 我们如何做一个 reverse() 不区分大小写?
            【解决方案12】:
            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;
                    }
                }
            }
            

            【讨论】:

              【解决方案13】:

              如果您难以理解,这可能会有所帮助:

              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/

              【讨论】:

                【解决方案14】:

                我将最佳答案包装在一个 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,因为这个 Array 方法在 ECMAScript 规范中是没有的。
                【解决方案15】:

                将您的字符串包装在/ /i 中。这是使用正则表达式忽略大小写的简单方法

                【讨论】:

                • 问题是关于排序,而不是匹配。
                猜你喜欢
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2021-10-19
                • 1970-01-01
                • 1970-01-01
                • 2018-09-29
                • 1970-01-01
                • 1970-01-01
                相关资源
                最近更新 更多