Javascript 如何在多列上对数组进行排序?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2784230/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-23 01:54:15  来源:igfitidea点击:

How do you sort an array on multiple columns?

javascriptalgorithmsorting

提问by flavour404

I have a multidimensional array. The primary array is an array of

我有一个多维数组。主要数组是一个数组

[publicationID][publication_name][ownderID][owner_name] 

What I am trying to do is sort the array by owner_nameand then by publication_name. I know in JavaScript you have Array.sort(), into which you can put a custom function, in my case i have:

我想要做的是对数组进行排序owner_name,然后再排序publication_name。我知道在 JavaScript 中你有Array.sort(),你可以在其中放置一个自定义函数,在我的情况下,我有:

function mysortfunction(a, b) {
    var x = a[3].toLowerCase();
    var y = b[3].toLowerCase();

    return ((x < y) ? -1 : ((x > y) ? 1 : 0));
}

This is fine for just sorting on the one column, namely owner_name, but how do I modify it to sort on owner_name, then publication_name?

这是刚刚排序的一列,即OWNER_NAME很好,但我怎样修改它进行排序owner_name,然后publication_name

回答by dcp

If owner names differ, sort by them. Otherwise, use publication name for tiebreaker.

如果所有者名称不同,请按它们排序。否则,对决胜局使用出版物名称。

function mysortfunction(a, b) {

  var o1 = a[3].toLowerCase();
  var o2 = b[3].toLowerCase();

  var p1 = a[1].toLowerCase();
  var p2 = b[1].toLowerCase();

  if (o1 < o2) return -1;
  if (o1 > o2) return 1;
  if (p1 < p2) return -1;
  if (p1 > p2) return 1;
  return 0;
}

回答by Teun D

I think what you're looking for is thenBy.js: https://github.com/Teun/thenBy.js

我想你要找的是 thenBy.js:https: //github.com/Teun/thenBy.js

It allows you to use the standard Array.sort, but with firstBy().thenBy().thenBy()style.

它允许您使用标准的 Array.sort,但具有firstBy().thenBy().thenBy()样式。

An example can be seen here.

一个例子可以在这里看到

回答by tbranyen

A good way to sort on many fields that are strings is to use toLocaleCompareand the boolean operator ||.

对许多字符串字段进行排序的一种好方法是使用toLocaleCompare和 布尔运算符||

Something like:

就像是:

// Sorting record releases by name and then by title.
releases.sort((oldRelease, newRelease) => {
  const compareName = oldRelease.name.localeCompare(newRelease.name);
  const compareTitle = oldRelease.title.localeCompare(newRelease.title);

  return compareName || compareTitle;
})

If you wanted to sort on more fields, you could simply chain them off the return statement with more boolean operators.

如果你想对更多的字段进行排序,你可以简单地用更多的布尔运算符将它们从 return 语句链接起来。

回答by bitless

Came across a need to do SQL-style mixed asc and desc object array sorts by keys.

遇到需要按键进行 SQL 风格的混合 asc 和 desc 对象数组排序。

kennebec's solution above helped me get to this:

上面 kennebec 的解决方案帮助我解决了这个问题:

Array.prototype.keySort = function(keys) {

keys = keys || {};

// via
// https://stackoverflow.com/questions/5223/length-of-javascript-object-ie-associative-array
var obLen = function(obj) {
    var size = 0, key;
    for (key in obj) {
        if (obj.hasOwnProperty(key))
            size++;
    }
    return size;
};

// avoiding using Object.keys because I guess did it have IE8 issues?
// else var obIx = function(obj, ix){ return Object.keys(obj)[ix]; } or
// whatever
var obIx = function(obj, ix) {
    var size = 0, key;
    for (key in obj) {
        if (obj.hasOwnProperty(key)) {
            if (size == ix)
                return key;
            size++;
        }
    }
    return false;
};

var keySort = function(a, b, d) {
    d = d !== null ? d : 1;
    // a = a.toLowerCase(); // this breaks numbers
    // b = b.toLowerCase();
    if (a == b)
        return 0;
    return a > b ? 1 * d : -1 * d;
};

var KL = obLen(keys);

if (!KL)
    return this.sort(keySort);

for ( var k in keys) {
    // asc unless desc or skip
    keys[k] = 
            keys[k] == 'desc' || keys[k] == -1  ? -1 
          : (keys[k] == 'skip' || keys[k] === 0 ? 0 
          : 1);
}

this.sort(function(a, b) {
    var sorted = 0, ix = 0;

    while (sorted === 0 && ix < KL) {
        var k = obIx(keys, ix);
        if (k) {
            var dir = keys[k];
            sorted = keySort(a[k], b[k], dir);
            ix++;
        }
    }
    return sorted;
});
return this;
};

sample usage:

示例用法:

var obja = [
  {USER:"bob",  SCORE:2000, TIME:32,    AGE:16, COUNTRY:"US"},
  {USER:"jane", SCORE:4000, TIME:35,    AGE:16, COUNTRY:"DE"},
  {USER:"tim",  SCORE:1000, TIME:30,    AGE:17, COUNTRY:"UK"},
  {USER:"mary", SCORE:1500, TIME:31,    AGE:19, COUNTRY:"PL"},
  {USER:"joe",  SCORE:2500, TIME:33,    AGE:18, COUNTRY:"US"},
  {USER:"sally",    SCORE:2000, TIME:30,    AGE:16, COUNTRY:"CA"},
  {USER:"yuri", SCORE:3000, TIME:34,    AGE:19, COUNTRY:"RU"},
  {USER:"anita",    SCORE:2500, TIME:32,    AGE:17, COUNTRY:"LV"},
  {USER:"mark", SCORE:2000, TIME:30,    AGE:18, COUNTRY:"DE"},
  {USER:"amy",  SCORE:1500, TIME:29,    AGE:19, COUNTRY:"UK"}
];

var sorto = {
  SCORE:"desc",TIME:"asc", AGE:"asc"
};

obja.keySort(sorto);

yields the following:

产生以下结果:

 0: {     USER: jane;     SCORE: 4000;    TIME: 35;       AGE: 16;    COUNTRY: DE;   }
 1: {     USER: yuri;     SCORE: 3000;    TIME: 34;       AGE: 19;    COUNTRY: RU;   }
 2: {     USER: anita;    SCORE: 2500;    TIME: 32;       AGE: 17;    COUNTRY: LV;   }
 3: {     USER: joe;      SCORE: 2500;    TIME: 33;       AGE: 18;    COUNTRY: US;   }
 4: {     USER: sally;    SCORE: 2000;    TIME: 30;       AGE: 16;    COUNTRY: CA;   }
 5: {     USER: mark;     SCORE: 2000;    TIME: 30;       AGE: 18;    COUNTRY: DE;   }
 6: {     USER: bob;      SCORE: 2000;    TIME: 32;       AGE: 16;    COUNTRY: US;   }
 7: {     USER: amy;      SCORE: 1500;    TIME: 29;       AGE: 19;    COUNTRY: UK;   }
 8: {     USER: mary;     SCORE: 1500;    TIME: 31;       AGE: 19;    COUNTRY: PL;   }
 9: {     USER: tim;      SCORE: 1000;    TIME: 30;       AGE: 17;    COUNTRY: UK;   }
 keySort: {  }

(using a print function from here)

(使用此处的打印功能)

here is a jsbin example.

这是一个 jsbin 示例

edit: cleaned up and posted as mksort.js on github.

编辑:清理并在 github 上作为 mksort.js 发布

回答by kennebec

This is handy for alpha sorts of all sizes. Pass it the indexes you want to sort by, in order, as arguments.

这对于所有大小的 alpha 类型都很方便。将要排序的索引按顺序传递给它作为参数。

Array.prototype.deepSortAlpha= function(){
    var itm, L=arguments.length, order=arguments;

    var alphaSort= function(a, b){
        a= a.toLowerCase();
        b= b.toLowerCase();
        if(a== b) return 0;
        return a> b? 1:-1;
    }
    if(!L) return this.sort(alphaSort);

    this.sort(function(a, b){
        var tem= 0,  indx=0;
        while(tem==0 && indx<L){
            itm=order[indx];
            tem= alphaSort(a[itm], b[itm]); 
            indx+=1;        
        }
        return tem;
    });
    return this;
}

var arr= [[ "Nilesh","Karmshil"], ["Pranjal","Deka"], ["Susants","Ghosh"],
["Shiv","Shankar"], ["Javid","Ghosh"], ["Shaher","Banu"], ["Javid","Rashid"]];

arr.deepSortAlpha(1,0);

回答by Nina Scholz

I suggest to use a built in comparer and chain the wanted sort order with logical or ||.

我建议使用内置的比较器并将所需的排序顺序与逻辑或||.

function customSort(a, b) {
    return a[3].localeCompare(b[3]) || a[1].localeCompare(b[1]);
}

Working example:

工作示例:

var array = [
    [0, 'Aluminium', 0, 'Francis'],
    [1, 'Argon', 1, 'Ada'],
    [2, 'Brom', 2, 'John'],
    [3, 'Cadmium', 3, 'Marie'],
    [4, 'Fluor', 3, 'Marie'],
    [5, 'Gold', 1, 'Ada'],
    [6, 'Kupfer', 4, 'Ines'],
    [7, 'Krypton', 4, 'Joe'],
    [8, 'Sauerstoff', 3, 'Marie'],
    [9, 'Zink', 5, 'Max']
];

array.sort(function (a, b) {
    return a[3].localeCompare(b[3]) || a[1].localeCompare(b[1]);
});

document.write('<pre>');
array.forEach(function (a) {
    document.write(JSON.stringify(a) + '<br>');
});

回答by Tmac

You could concat the 2 variables together into a sortkey and use that for your comparison.

您可以将 2 个变量连接到一个排序键中,并将其用于比较。

list.sort(function(a,b){
   var aCat = a.var1 + a.var2;
   var bCat = b.var1 + b.var2;
   return (aCat > bCat ? 1 : aCat < bCat ? -1 : 0);
});

回答by MiF

I found multisotr. This is simple, powerfull and small library for multiple sorting. I was need to sort an array of objects with dynamics sorting criteria:

我找到了multisotr。这是一个用于多重排序的简单、强大和小型的库。我需要使用动态排序标准对一组对象进行排序:

const criteria = ['name', 'speciality']
const data = [
  { name: 'Mike', speciality: 'JS', age: 22 },
  { name: 'Tom', speciality: 'Java', age: 30 },
  { name: 'Mike', speciality: 'PHP', age: 40 },
  { name: 'Abby', speciality: 'Design', age: 20 },
]

const sorted = multisort(data, criteria)

console.log(sorted)
<script src="https://cdn.rawgit.com/peterkhayes/multisort/master/multisort.js"></script>

This library more mutch powerful, that was my case. Try it.

这个库更强大,这就是我的情况。尝试一下。

回答by WebWanderer

I was working with ng-gridand needed to to multiple column sorting on an array of records returned from an API, so I came up with this nifty, dynamic multi-sort function.

我正在使用ng-grid并需要对从 API 返回的记录数组进行多列排序,所以我想出了这个漂亮的动态多排序函数。

First of all, ng-gridfires an "event" for "ngGridSorted" and passes this structure back, describing the sort:

首先,ng-grid为“ngGridSorted”触发一个“事件”并将这个结构传回,描述排序:

sortData = {
    columns:    DOM Element,
    directions: [], //Array of string values desc or asc. Each index relating to the same index of fields
    fields:     [], //Array of string values
};

So I built a function that will dynamically generate a sort function based on the sortDataas shown above (Don't be scared by the scroll bar! It's only about 50 lines long! Also, I'm sorry about the slop. It prevented a horizontal scrollbar!):

所以我构建了一个函数,它会根据上sortData图动态生成排序函数(不要被滚动条吓到!它只有大约 50 行长!另外,我对 slop 感到抱歉。它阻止了水平滚动条!):

function SortingFunction(sortData)
{
    this.sortData = sortData;

    this.sort = function(a, b)
    {
        var retval = 0;

        if(this.sortData.fields.length)
        {
            var i = 0;

            /*
                Determine if there is a column that both entities (a and b)
                have that are not exactly equal. The first one that we find
                will be the column we sort on. If a valid column is not
                located, then we will return 0 (equal).
            */
            while(  (   !a.hasOwnProperty(this.sortData.fields[i]) 
                    ||  !b.hasOwnProperty(this.sortData.fields[i]) 
                    ||  (a.hasOwnProperty(this.sortData.fields[i]) 
                        && b.hasOwnProperty(this.sortData.fields[i]) 
                        && a[this.sortData.fields[i]] === b[this.sortData.fields[i]])
                    ) && i < this.sortData.fields.length){
                i++;
            }

            if(i < this.sortData.fields.length)
            {
                /*
                    A valid column was located for both entities
                    in the SortData. Now perform the sort.
                */
                if(this.sortData.directions 
                && i < this.sortData.directions.length 
                && this.sortData.directions[i] === 'desc')
                {
                    if(a[this.sortData.fields[i]] > b[this.sortData.fields[i]])
                        retval = -1;
                    else if(a[this.sortData.fields[i]] < b[this.sortData.fields[i]])
                        retval = 1;
                }
                else
                {
                    if(a[this.sortData.fields[i]] < b[this.sortData.fields[i]])
                        retval = -1;
                    else if(a[this.sortData.fields[i]] > b[this.sortData.fields[i]])
                        retval = 1;
                }
            }
        }

        return retval;
    }.bind(this);
}

I then sort the results of my API (results) like so:

然后我对 API ( results)的结果进行排序,如下所示:

results.sort(new SortingFunction(sortData).sort);

I hope somebody else enjoys this solution as much as I do! Thanks!

我希望其他人和我一样喜欢这个解决方案!谢谢!

回答by Lewiss

function multiSort() {

    var args =$.makeArray( arguments ),
        sortOrder=1, prop='', aa='',  b='';

    return function (a, b) {

       for (var i=0; i<args.length; i++){

         if(args[i][0]==='-'){
            prop=args[i].substr(1)
            sortOrder=-1
         }
         else{sortOrder=1; prop=args[i]}

         aa = a[prop].toLowerCase()
         bb = b[prop].toLowerCase()

         if (aa < bb) return -1 * sortOrder;
         if (aa > bb) return 1 * sortOrder;

       }

       return 0
    }

}
empArray.sort(multiSort( 'lastname','firstname')) Reverse with '-lastname'