【问题标题】:javascript sorting array of mixed strings and null valuesjavascript对混合字符串和空值的数组进行排序
【发布时间】:2010-02-24 18:43:02
【问题描述】:

当对由字符串、空值和零混合组成的数组进行排序时,我得到的结果并不像预期的那样正确,空值似乎被排序为“空”字符串。 我这样做了(在 FireFox 上测试过):

var arr1 = arr2 = [null, "b", "c", "d", null, "e", 0, "g", null, 0, "h", "i", "l", "m", "n", "o", "p", "ne", "nur", "nimbus"];

document.write("SORTED ARRAY:<br>");
arr1.sort();
arr1.forEach(function(val){document.write(val + "; ")});

结果是:

排序数组: 0; 0;乙; C; d; e; G; H;一世; l;米; n; ne;雨云;空值;空值;空值;努尔; ○; p;

您是否知道如何在数组排序期间将空值视为空字符串,以便它们与零一起出现在排序数组中的第一个。

谢谢!

【问题讨论】:

  • 您需要在字符串之前对数字进行排序吗?字典顺序与数字不同。考虑订购 { 100, 15 } 和 { "100", "15" } 作为示例。
  • @andras:不,只是零。

标签: javascript arrays sorting


【解决方案1】:

这将通过将所有内容转换为字符串(特别是将 null 转换为空字符串)并允许 JavaScript 的内置字符串比较来完成您想要的工作:

arr2.sort( function(a, b) 
{
    /* 
       We avoid reuse of arguments variables in a sort
       comparison function because of a bug in IE <= 8.
       See http://www.zachleat.com/web/array-sort/
    */
    var va = (a === null) ? "" : "" + a,
        vb = (b === null) ? "" : "" + b;

    return va > vb ? 1 : ( va === vb ? 0 : -1 );
} );

【讨论】:

  • 如果他有数字,这将无法正确排序。你需要更多的三元组。
  • @andras 如果正确的意思是 20 在 5 之前,那么默认排序也有同样的问题
  • @andras, @Alexandre:最初的问题确实说数组有零、字符串和空值,所以我不确定是否需要正确处理数字,但我同意你的观点。
  • @Tim:听起来很棒,谢谢!怎么办:a = a || ""; b = b || "";
  • @Marco:这有两个问题:首先,零和null 都将被转换为空字符串,这意味着排序不会区分空值和零(除非这不是问题为你)。其次,非零数字不会转换成字符串,而数字与不能转换成数字的字符串(如"d")的比较总是返回false,所以不会像你期望的那样排序。
【解决方案2】:
[null, "b", "c", "d", null, "e", 0, "g", null, 0, "h", "i", "l", "m", "n", "o", "p", "ne", "nur", "nimbus"].sort(function (a,b) { 
   return a === null ? -1 : b === null ? 1 : a.toString().localeCompare(b);
});

【讨论】:

  • 啊,是的,我忘了localeCompare。 +1。
  • 请注意,如果 abnull,则此实现无法处理,这应该返回 0。通常它并不重要,但取决于回调的使用方式,它可能很重要。
【解决方案3】:

我遇到了这个线程,正在寻找一个类似的快速而肮脏的答案,但它并没有触及我真正需要的东西。 “如何处理空值”,将它们浮动到顶部或底部等。这就是我想出的:

    var list = [0, -1, 1, -1, 0, null, 1];

var sorter = function(direction){

    // returns a sort function which treats `null` as a special case, either 'always higher' (1)
    // or 'always lower' (-1)

    direction = direction || 1;
    var up = direction > 0;

    return function(a, b){

        var r = -1,
            aa = a == null ? undefined : a,
            bb = b == null ? undefined : b,
            careabout = up ? aa : bb
        ;

        if(aa == bb){
            r = 0;
        }else if(aa > bb || careabout == undefined){
            r = 1
        }
        return r;

    }

}

var higher = [].concat(list.sort(sorter(1)));    
var lower = [].concat(list.sort(sorter(-1)));

console.log(lower[0] === null, lower);
console.log(higher[higher.length - 1] === null, higher);

// then, something that sorts something in a direction can use that direction to
// determine where the nulls end up. `list` above ranged from negative-one to one, 
// with mixed zero and null values in between. If we want to view that list 
// from highest value to descending, we'd want the nulls to be treated as 
// 'always lower' so they appear at the end of the list.
// If we wanted to view the list from lowest value to highest value we'd want the
// nulls to be treated as `higher-than-anything` so they would appear at the bottom
// list.

var sortThisArray = function(arr, direction){
    var s = sorter(direction);
    return arr.sort(function(a,b){
       return direction * s(a,b) 
    });
}

console.log(sortThisArray(list, 1));
console.log(sortThisArray(list, -1));

【讨论】:

    【解决方案4】:

    我还不能对答案发表评论,但我想分享我的问题,以防其他人使用 Tims 解决方案。

    Tims 解决方案效果很好。但是...它会间歇性地抛出“预期数字”错误。完全随机。

    此链接解释了问题以及为我解决了该问题的解决方法...

    http://www.zachleat.com/web/array-sort/

    希望这可以节省我浪费在调试/谷歌搜索上的时间!

    【讨论】:

    【解决方案5】:

    我还不能为@robert 的评论添加评论,但这里是@robert 的扩展以添加对布尔值的支持:

    [null, "b", "c", "d", null, "e", 0, undefined, "g", null, 0, "h", "i", true, "l", "m", undefined, "n", "o", "p", false, "ne", "nur", "nimbus"].sort(function (a,b) { 
        if (a === b) { return 0; }
        if (a === null) {
            return -1;
        } else if (b === null) {
            return 1;
        } else if (typeof a === 'string') {
            return a.localeCompare(b);
        } else if (typeof a === 'number' || typeof a === 'boolean') {
            if (a < b) return -1;
            if (a > b) return 1;
        }
        return 0;
    });
    

    另外,根据 JS 规范,未定义的总是被引导到数组的末尾...

    【讨论】:

      【解决方案6】:

      使用以这种方式处理空值的自定义排序函数。

      arr1.sort(function(a, b) {
          if (a===null) a='';
          if (b===null) b='';
      
          if (''+a < ''+b) return -1;
          if (''+a > ''+b) return  1;
      
          return 0;
      });
      

      【讨论】:

      • 第一行当然应该是:if (a===null) a='';
      【解决方案7】:

      我们可以用最简单的方式做到这一点

      sort: (a, b) => {
              a = a.name || '';
              b = b.name || '';
              return a.localeCompare(b);
          }
      

      【讨论】:

        【解决方案8】:

        我建议对具有混合值(数字、字符串、空值、未定义值)的数组进行升序排序。

        const arr = [null, 'b46', '+', 'Яромир Ягр', '76region', 2, 9999999, 'Эркер', '', 0, 3, 33, 765, '366', '77rus', 'ааэ', null, null, '200', undefined, 'ААА', '1', '40', 88, 'cat', undefined, 'apple', 4, '55555', 777, 12, 6, 0, '55', 8, null, undefined, '  Жу', 'жа', 'bbbb', '    Xz', '  Z', 'aa', undefined];
        
        const sortAsc = (arr) => {
          const undefinedAndNulls = arr.filter(val => val === null || val === undefined);
          const numbers = arr.filter(val => !isNaN(val) && val !== null);
          const sortedNumbers = numbers.sort((a, b) => a - b);
          const rest = arr.filter(val => val && isNaN(val));
          const sortedRest = rest.sort((a, b) => {
            const val1 = a || '';
            const val2 = b || '';
            const valueA = val1.toString().trimLeft();
            const valueB = val2.toString().trimLeft();
            return valueA.localeCompare(valueB);
          });
          return [...undefinedAndNulls, ...sortedNumbers, ...sortedRest];
        };
        

        结果:

        [null, null, null, undefined, undefined, null, undefined, undefined, '', 0, 0, '1', 2, 3, 4, 6, 8, 12, 33, '40', '55', 88, '200', '366', 765, 777, '55555', 9999999, '+', '76region', '77rus', 'aa', 'apple', 'b46', 'bbbb', 'cat', '    Xz', '  Z', 'ААА', 'ааэ', 'жа', '  Жу', 'Эркер', 'Яромир Ягр'];
        

        【讨论】:

          【解决方案9】:

          由于我一直有不同的用例来对诸如 null 和 undefined 之类的内容进行排序,因此我创建了以下函数来使用一组选项创建比较器。将其添加到此处以防对其他人有用。

          请注意,此函数目前不处理 NaN 和其他情况,如混合类型,但这些可以很容易地作为选项添加。

          用法示例:

          array.sort(createComparator({
             property: 'path.to.property',
             direction: 'desc',
             sortNulls: 'top',
             caseSensitive: true,
          });
          
          array.sort(createComparator({
             accessor: value => value.date.valueOf(),
             direction: 'desc',
             sortNulls: 'top',
             caseSensitive: true,
          });
          

          代码是:

          import get from 'lodash/get';
          
          /**
           * Creates a comparator function for sorting given a set of options.
           *
           * @param {String}   options.property       
           *                   The path to the property to sort by
           *                   
           * @param {Function} options.accessor       
           *                   The function used to calculate the property to sort by. Takes the 
           *                   item being sorted and returns the value to use for the sorting 
           *                   comparison
           *                   
           * @param {String}   options.direction      
           *                   The direction of sort: `asc` or `desc`. Defaults to `asc`
           *                   
           * @param {String}   options.sortNulls      
           *                   Where null values should be sorted: `top` or `bottom`. Defaults 
           *                   to `top`
           *                   
           * @param {String}   options.sortUndefineds 
           *                   Where undefined values should be sorted: `top` or `bottom`. 
           *                   Defaults to the value of `sortNulls`
           *                   
           * @param {boolean}  options.caseSensitive  
           *                   Whether to compare strings with the case of letters affecting 
           *                   the sort. Defaults to `false`
           *
           * @return {Function} A comparator function that can be used with `Array.sort` to 
           *                    sort an array
           */
          function createComparator({
            property,
            accessor,
            direction = 'asc',
            sortNulls = 'top',
            sortUndefineds,
            caseSensitive = false,
          }) {
            const topNulls = sortNulls === 'top';
          
            // Convert binary parameters to boolean to avoid doing it for each comparison
            return advancedComparator.bind(null, {
              accessor: property ? value => get(value, property) : accessor,
              desc: direction === 'desc' ? -1 : 1,
              topNulls,
              topUndefineds: sortUndefineds != null ? sortUndefineds === 'top' : topNulls,
              caseSensitive,
            });
          }
          
          function advancedComparator(options, a, b) {
            const { accessor, desc, topNulls, topUndefineds, caseSensitive } = options;
          
            a = accessor ? accessor(a) : a;
            b = accessor ? accessor(b) : b;
          
            if (a === null) {
              return b === null ? 0 : (topNulls ? -1 : 1);
            } else if (b === null) {
              return (topNulls ? 1 : -1);
            }
          
            if (typeof a === 'undefined') {
              return typeof b === 'undefined' ? 0 : (topUndefineds ? -1 : 1);
            } else if (typeof b === 'undefined') {
              return (topUndefineds ? 1 : -1);
            }
          
            if (!caseSensitive) {
              a = typeof a === 'string' ? a.toLowerCase() : a;
              b = typeof b === 'string' ? b.toLowerCase() : b;
            }
          
            if (typeof a === 'string' && typeof b === 'string') {
              return a.localeCompare(b);
            }
          
            if (a > b) { return 1 * desc; }
            if (a < b) { return -1 * desc; }
          
            return 0;
          }
          

          【讨论】:

            【解决方案10】:

            您可以将排序传递给排序函数

            array.sort(sortfunction)
            

            sortfunction 在哪里进行您需要的比较(空值大于其他值的常规排序)

            【讨论】:

              【解决方案11】:

              浏览器正在执行 null.toString();因为 null 是一个对象,所以这几乎是 Object.toString()... 这将返回“null”

              传入一个参数进行排序,作为你的比较函数[如果函数返回大于0的值,b的排序小于a]

              功能基本上是:

              comparisonFunc = function(a, b)
              {
               if((a === null) && (b === null)) return 0; //they're both null and equal
               else if((a === null) && (b != null)) return -1; //move a downwards
               else if((a != null) && (b === null)) return 1; //move b downwards
               else{
                //Lexicographical sorting goes here
               }
              }
              set.sort(comparisonFunc);
              

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 2023-03-30
                • 1970-01-01
                • 2015-10-14
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                相关资源
                最近更新 更多