【问题标题】:sort Javascript array by two numeric fields按两个数字字段对 Javascript 数组进行排序
【发布时间】:2011-09-02 01:32:43
【问题描述】:
grouperArray.sort(function (a, b) {
    var aSize = a.gsize;
    var bSize = b.gsize;
    var aLow = a.glow;
    var bLow = b.glow;
    console.log(aLow + " | " + bLow);      
    return (aSize < bSize) ? -1 : (aSize > bSize) ? 1 : 0;
});

此代码按gsize 对数组进行排序,从小到大。

如何将其更改为首先按gsize 排序,然后按glow

【问题讨论】:

  • 排序功能对正数、负数或零结果作出反应。所以你可以写:“return aSize - bSize”。这将是更简单易读的代码。
  • 顶部answer,压缩:col0然后col1(升序)排序对象数组: myArray.sort(function(a,b){return a.col0-b.col0||a.col1-b.col1}); 替代示例:排序数组按索引 #0 排列的数组,然后是 #2,然后是 #1(降序): myArray.sort(function(a,b){return b[0]-a[0]||b[2]-a[2]||b[1]-a[1]});

标签: javascript arrays sorting


【解决方案1】:
grouperArray.sort(function (a, b) {   
    return a.gsize - b.gsize || a.glow - b.glow;
});

更短的版本

【讨论】:

  • 很棒的捷径!帮我把一个更复杂的解决方案放在一起.. stackoverflow.com/questions/6101475/…
  • 又好又干净!唯一它只适用于数字。
  • 你能解释一下这里的逻辑吗?!。 sort an array with a key's value first 然后sort the result with another key's value 对我有用
  • @KTM 逻辑如下:如果两个gsize相等,则条件的第一部分等于0,即为假,执行条件的第二部分。
  • @Scalpweb 是的 :) 所以这可以用任意数量的键对数组进行排序,对吧?!不错的技巧
【解决方案2】:
grouperArray.sort(function (a, b) {
    var aSize = a.gsize;
    var bSize = b.gsize;
    var aLow = a.glow;
    var bLow = b.glow;
    console.log(aLow + " | " + bLow);

    if(aSize == bSize)
    {
        return (aLow < bLow) ? -1 : (aLow > bLow) ? 1 : 0;
    }
    else
    {
        return (aSize < bSize) ? -1 : 1;
    }
});

【讨论】:

  • 为了使用箭头语法更简洁,而不使用其他答案中显示的非显而易见的技术:grouperArray.sort((a, b) =&gt; a.gsize == b.gsize ? a.glow - b.glow : a.gsize - b.gsize。为了使代码更容易理解,我们对== 保持明确的测试。
  • 天哪...谢谢@ToolmakerSteve。
  • 简单有效
【解决方案3】:
grouperArray.sort((a, b) => a.gsize - b.gsize || a.glow - b.glow);

使用箭头语法的更短版本!

【讨论】:

【解决方案4】:

我意识到这是不久前提出的,但我想我会添加我的解决方案。

此函数动态生成排序方法。只需提供每个可排序的子属性名称,前面加上 +/- 以指示升序或降序。超级可重用,它不需要知道任何关于你放在一起的数据结构。可以证明是白痴 - 但似乎没有必要。

function getSortMethod(){
    var _args = Array.prototype.slice.call(arguments);
    return function(a, b){
        for(var x in _args){
            var ax = a[_args[x].substring(1)];
            var bx = b[_args[x].substring(1)];
            var cx;

            ax = typeof ax == "string" ? ax.toLowerCase() : ax / 1;
            bx = typeof bx == "string" ? bx.toLowerCase() : bx / 1;

            if(_args[x].substring(0,1) == "-"){cx = ax; ax = bx; bx = cx;}
            if(ax != bx){return ax < bx ? -1 : 1;}
        }
    }
}

示例用法:

items.sort(getSortMethod('-price', '+priority', '+name'));

这会将items 与最低price 排在最前面,并排到priority 最高的项目。 name 项目打破了进一步的联系

其中 items 是一个数组,例如:

var items = [
    { name: "z - test item", price: "99.99", priority: 0, reviews: 309, rating: 2 },
    { name: "z - test item", price: "1.99", priority: 0, reviews: 11, rating: 0.5 },
    { name: "y - test item", price: "99.99", priority: 1, reviews: 99, rating: 1 },
    { name: "y - test item", price: "0", priority: 1, reviews: 394, rating: 3.5 },
    { name: "x - test item", price: "0", priority: 2, reviews: 249, rating: 0.5 } ...
];

现场演示:http://gregtaff.com/misc/multi_field_sort/

编辑:修复了 Chrome 的问题。

【讨论】:

  • 这太棒了
  • 天才答案!
  • 对于打字稿(因为没有得到error TS2554: Expected 0 arguments, but got ..)使用这里的语法:stackoverflow.com/a/4116634/5287221
【解决方案5】:

我希望ternary 运算符((aSize &lt; bSize) ? -1 : (aSize &gt; bSize) ? 1 : 0;) 让您感到困惑。您应该查看该链接以更好地理解它。

在此之前,您的代码将在 if/else 中完整呈现。

grouperArray.sort(function (a, b) {
    if (a.gsize < b.gsize)
    {
        return -1;
    }
    else if (a.gsize > b.gsize)
    {
        return 1;
    }
    else
    {
        if (a.glow < b.glow)
        {
            return -1;
        }
        else if (a.glow > b.glow)
        {
            return 1;
        }
        return 0;
    }
});

【讨论】:

    【解决方案6】:

    对于那些可能想要更通用的东西来处理任意数量的字段的人来说,这是一个实现。

    Array.prototype.sortBy = function (propertyName, sortDirection) {
    
        var sortArguments = arguments;
        this.sort(function (objA, objB) {
    
            var result = 0;
            for (var argIndex = 0; argIndex < sortArguments.length && result === 0; argIndex += 2) {
    
                var propertyName = sortArguments[argIndex];
                result = (objA[propertyName] < objB[propertyName]) ? -1 : (objA[propertyName] > objB[propertyName]) ? 1 : 0;
    
                //Reverse if sort order is false (DESC)
                result *= !sortArguments[argIndex + 1] ? 1 : -1;
            }
            return result;
        });
    
    }
    

    基本上,您可以指定任意数量的属性名称/排序方向:

    var arr = [{
      LastName: "Doe",
      FirstName: "John",
      Age: 28
    }, {
      LastName: "Doe",
      FirstName: "Jane",
      Age: 28
    }, {
      LastName: "Foo",
      FirstName: "John",
      Age: 30
    }];
    
    arr.sortBy("LastName", true, "FirstName", true, "Age", false);
    //Will return Jane Doe / John Doe / John Foo
    
    arr.sortBy("Age", false, "LastName", true, "FirstName", false);
    //Will return John Foo / John Doe / Jane Doe
    

    【讨论】:

      【解决方案7】:
      grouperArray.sort(function (a, b) {
        var aSize = a.gsize;
        var bSize = b.gsize;
        var aLow = a.glow;
        var bLow = b.glow;
        console.log(aLow + " | " + bLow);      
        return (aSize < bSize) ? -1 : (aSize > bSize) ? 1 : ( (aLow < bLow ) ? -1 : (aLow > bLow ) ? 1 : 0 );
      });
      

      【讨论】:

        【解决方案8】:
        grouperArray.sort(function (a, b) {
             var aSize = a.gsize;     
             var bSize = b.gsize;     
             var aLow = a.glow;
             var bLow = b.glow;
             console.log(aLow + " | " + bLow);
             return (aSize < bSize) ? -1 : (aSize > bSize) ? 1 : (aLow < bLow) ? -1 : (aLow > bLow) ? 1 : 0); }); 
        

        【讨论】:

          【解决方案9】:

          这是一个实现,它使用递归按从 1 到无限的任意数量的排序字段进行排序。您向它传递一个 results 数组,它是一个要排序的结果对象数组,以及一个 sorts 数组,它是一个定义排序的排序对象数组。每个排序对象都必须有一个“select”键作为它排序的键名和一个“order”键,它是一个表示“升序”或“降序”的字符串。

          sortMultiCompare = (a, b, sorts) => {
              let select = sorts[0].select
              let order = sorts[0].order
              if (a[select] < b[select]) {
                  return order == 'ascending' ? -1 : 1
              } 
              if (a[select] > b[select]) {
                  return order == 'ascending' ? 1 : -1
              }
              if(sorts.length > 1) {
                  let remainingSorts = sorts.slice(1)
                  return this.sortMultiCompare(a, b, remainingSorts)
              }
              return 0
          }
          
          sortResults = (results, sorts) => {
              return results.sort((a, b) => {
                  return this.sortMultiCompare(a, b, sorts)
              })
          }
          
          // example inputs
          const results = [
              {
                  "LastName": "Doe",
                  "FirstName": "John",
                  "MiddleName": "Bill"
              },
              {
                  "LastName": "Doe",
                  "FirstName": "Jane",
                  "MiddleName": "Bill"
              },
              {
                  "LastName": "Johnson",
                  "FirstName": "Kevin",
                  "MiddleName": "Bill"
              }
          ]
          
          const sorts = [
              {
                  "select": "LastName",
                  "order": "ascending"
              },
              {
                  "select": "FirstName",
                  "order": "ascending"
              },
              {
                  "select": "MiddleName",
                  "order": "ascending"
              }    
          ]
          
          // call the function like this:
          let sortedResults = sortResults(results, sorts)
          

          【讨论】:

            【解决方案10】:

            使用 MULTIPLE 键的动态方式:

            • 从每个排序的 col/key 中过滤唯一值
            • 排序或倒序
            • 根据 indexOf(value) 键值为每个对象添加权重宽度 zeropad
            • 使用计算权重排序

            Object.defineProperty(Array.prototype, 'orderBy', {
            value: function(sorts) { 
                sorts.map(sort => {            
                    sort.uniques = Array.from(
                        new Set(this.map(obj => obj[sort.key]))
                    );
            
                    sort.uniques = sort.uniques.sort((a, b) => {
                        if (typeof a == 'string') {
                            return sort.inverse ? b.localeCompare(a) : a.localeCompare(b);
                        }
                        else if (typeof a == 'number') {
                            return sort.inverse ? (a < b) : (a > b ? 1 : 0);
                        }
                        else if (typeof a == 'boolean') {
                            let x = sort.inverse ? (a === b) ? 0 : a? -1 : 1 : (a === b) ? 0 : a? 1 : -1;
                            return x;
                        }
                        return 0;
                    });
                });
            
                const weightOfObject = (obj) => {
                    let weight = "";
                    sorts.map(sort => {
                        let zeropad = `${sort.uniques.length}`.length;
                        weight += sort.uniques.indexOf(obj[sort.key]).toString().padStart(zeropad, '0');
                    });
                    //obj.weight = weight; // if you need to see weights
                    return weight;
                }
            
                this.sort((a, b) => {
                    return weightOfObject(a).localeCompare( weightOfObject(b) );
                });
            
                return this;
            }
            });
            

            用途:

            // works with string, number and boolean
            let sortered = your_array.orderBy([
                {key: "type", inverse: false}, 
                {key: "title", inverse: false},
                {key: "spot", inverse: false},
                {key: "internal", inverse: true}
            ]);
            

            【讨论】:

              【解决方案11】:

              这是我用的

              function sort(a, b) {
                  var _a = "".concat(a.size, a.glow);
                  var _b = "".concat(b.size, b.glow);
                  return _a < _b;
              }
              

              将这两个项目连接为一个字符串,它们将按字符串值排序。如果你愿意,你可以用 parseInt 包装 _a 和 _b 来比较它们,如果你知道它们是数字的话。

              【讨论】:

                【解决方案12】:

                这是针对这种情况的解决方案,当您有一个优先排序键时,它可能不存在于某些特定项目中,因此您必须按后备键排序。

                输入数据示例(id2 是优先排序键):

                const arr = [
                    {id: 1},
                    {id: 2, id2: 3},
                    {id: 4},
                    {id: 3},
                    {id: 10, id2: 2},
                    {id: 7},
                    {id: 6, id2: 1},
                    {id: 5},
                    {id: 9, id2: 2},
                    {id: 8},
                ];
                

                输出应该是:

                [ { id: 6, id2: 1 },
                  { id: 9, id2: 2 },
                  { id: 10, id2: 2 },
                  { id: 2, id2: 3 },
                  { id: 1 },
                  { id: 3 },
                  { id: 4 },
                  { id: 5 },
                  { id: 7 },
                  { id: 8 } ]
                

                比较器函数如下:

                arr.sort((a,b) => {
                  if(a.id2 || b.id2) {
                    if(a.id2 && b.id2) {
                      if(a.id2 === b.id2) {
                        return a.id - b.id;
                      }
                      return a.id2 - b.id2;
                    }
                    return a.id2 ? -1 : 1;
                  }
                  return a.id - b.id
                });
                

                附注如果 .id2.id 可以为零,请考虑使用typeof

                【讨论】:

                  【解决方案13】:

                  让我们简化一下。

                  假设你有一个数组数组:

                  let tmp = [
                      [0, 1],
                      [2, 1],
                      [1, 1],
                      [0, 0],
                      [2, 0],
                      [1, 0],
                      [0, 2],
                      [2, 2],
                      [1, 2],
                  ]
                  

                  执行:

                  tmp.sort((a, b) => {
                      if (a[1] != b[1])
                          return a[1] - b[1];
                      else
                          return a[0] - b[0];
                  })
                  

                  将产生:

                  [
                      [0, 0],
                      [1, 0],
                      [2, 0],
                      [0, 1],
                      [1, 1],
                      [2, 1],
                      [0, 2],
                      [1, 2],
                      [2, 2]
                  ]
                  

                  【讨论】:

                    【解决方案14】:
                    grouperArray.sort(
                      function(a,b){return a.gsize == b.gsize ? a.glow - b.glow : a.gsize - b.gsize}
                    );
                    

                    【讨论】:

                      【解决方案15】:
                      grouperArray.sort(function (a, b) {
                          var aSize = a.gsize;
                          var bSize = b.gsize;
                          if (aSize !== aSize)
                              return aSize - bSize;
                          return a.glow - b.glow;
                      });
                      

                      未测试,但我认为应该可以。

                      【讨论】:

                        【解决方案16】:

                        就我而言,我按参数“重要”和“日期”对通知列表进行排序

                        • 第 1 步:我按“重要”和“不重要”过滤通知

                          let importantNotifications = notifications.filter(
                                  (notification) => notification.isImportant);
                          
                            let unImportantNotifications = notifications.filter(
                                  (notification) => !notification.isImportant);
                          
                        • 第 2 步:我按日期对它们进行排序

                            sortByDate = (notifications) => {
                            return notifications.sort((notificationOne, notificationTwo) => {
                              return notificationOne.date - notificationTwo.date;
                            });
                          };
                          
                        • 第 3 步:合并它们

                          [
                              ...this.sortByDate(importantNotifications),
                              ...this.sortByDate(unImportantNotifications),
                            ];
                          

                        【讨论】:

                          【解决方案17】:

                          如果您乐于使用新的tidy.js package,您可以使用

                          tidy(input_array,
                            arrange(['var1', desc('var2')])
                          );
                          

                          【讨论】:

                            猜你喜欢
                            • 2012-10-24
                            • 2021-12-14
                            • 2013-02-21
                            • 1970-01-01
                            • 2019-06-28
                            • 1970-01-01
                            • 1970-01-01
                            • 2020-08-24
                            相关资源
                            最近更新 更多