2010-05-06 5 views
72

У меня есть многомерный массив. Основной массив представляет собой массивКак вы сортируете массив по нескольким столбцам?

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

То, что я пытаюсь сделать, это своего рода массив по 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)); 
} 

Это нормально для просто сортировка по одной колонке, а именно: OWNER_NAME, но как я могу изменить его сортировать по owner_name, затем publication_name?

ответ

113

Если имена владельцев отличаются, сортируйте их. В противном случае используйте название публикации для тай-брейка.

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

@dcp Я не вижу, как он может сортировать второй атрибут. Если вы не зациклируете столько, сколько количество выбранных столбцов. Правильно? например [[A, 10], [J, 15], [A, 5], [J, 5]] => [[A, 10], [A, 5], [J, 15], [J, 5]] ' –

+2

@ user26409021 - Нет, это неправильно. В конечном итоге это [[A, 5], [A, 10], [J, 5], [J, 15]]. Сначала он сортируется по первому атрибуту, и если они совпадают, то он сортируется по второму атрибуту. Таким образом, в вашем примере A появится до J. В случае, когда A является одним и тем же для двух элементов, тогда он будет использовать второй атрибут. Итак, для [A, 10], [A, 5], 5 приходит до 10, поэтому для упорядочения оно будет иметь [A, 5], [A, 10]. То, что вам не хватает, заключается в том, что mysortfunction вызывается несколько раз, когда вы используете Array.sort, пока сортировка не будет завершена. – dcp

+1

@dcp ну, недостающая часть в вашем ответе - это цикл. Ха-ха. Благодарю. В моей я повторяю вашу функцию так много, как выбранные столбцы. –

16

Это удобно для альфа-сортов всех размеров. Передайте им индексы, которые вы хотите отсортировать по порядку в качестве аргументов.

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); 
+0

май Как я узнаю откуда вы взяли эти данные [["Nilesh", "Karmshil"], ["Pranjal", "Deka"], ["Susants", "Ghosh"], ["Shiv", " Шанкар »], [« Джавид »,« Гош »], [« Шахер »,« Бану »], [« Джавид »,« Рашид »]]; – defau1t

19

Взаимозависимо от типа смешанного массива asc и desc в стиле SQL. Решение

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

использование образца:

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

дает следующее:

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: { } 

(с помощью функции печати из here)

here is a jsbin example.

Редактировать: cleaned up and posted as mksort.js on github.

42

Я думаю, что вы ищете является thenBy.js: https://github.com/Teun/thenBy.js

Это позволяет использовать стандартные Array.sort, но с firstBy().thenBy().thenBy() стилем.

An example can be seen here.

+0

Будьте осторожны с производительностью на больших наборах данных. Каждый раз, когда вызывается 'thenBy', все элементы массива снова зацикливаются. –

+2

Это определенно не так. Когда вы вызываете thenBy(), он создает новую функцию, которая инкапсулирует предыдущую.Во время сортировки javascript не будет строго «прокручивать» элементы, но он _will_ вызывает функцию, которую вы передаете ей много раз. Количество вызовов не изменится, используя thenBy. Для некоторых соображений производительности читайте: https://github.com/Teun/thenBy.js#a-word-on-performance –

+1

Я вижу, я был неправ, спасибо за то, что подумал о производительности. Возможно, добавьте примечание о соображениях памяти при создании замыканий с новыми функциями? –

6

Вы можете объединить 2 переменные вместе в sortkey и использовать их для сравнения.

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

@GustavoRodrigues может быть потому, что он слишком хрупкий. Он не смог бы отсортироваться по определенным клавишам ввода, поскольку он просто смешивает две части вместе без разделителя или другого различия. Рассмотрим, были ли var1 и var2 для элемента X «foo» и «baz», в то время как var1 для элемента Y был «foobar». Когда отсортированный X должен наступить первым, но в этом случае он будет вторым. Этот ответ можно было бы улучшить, но, как сказано, это просто небезопасно. –

0
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' 
4

Я предлагаю использовать встроенный в компараторе и цепях разыскиваемый порядка сортировки с логическим или ||.

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

Рабочий пример:

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

1

Я работал с ng-grid и нужно многократным колонку сортировки на массив записей, возвращенных из API, так что я придумал эта отличная динамическая функция мультисортировки.

Прежде всего, 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 
}; 

Так что я построил функцию, которая будет динамически генерировать функцию сортировки, основанный на sortData, как показано выше (не ли пугаться полосами прокрутки Это только около 50 линий Кроме того, я сожалею о отстойном Это предотвратило горизонтальную полосу прокрутки!.!):

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

Я тогда сортировать результаты моего API (results) как так:

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

Я надеюсь, что кто-то еще пользуется этим решением так много, как я! Благодаря!

+0

Какая опция столбцов используется для данных сортировки? –

7

Хороший способ сортировки по многим полям, которые являются строками, заключается в использовании toLocaleCompare и булевом операторе ||.

Что-то вроде:

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

Если вы хотите отсортировать по несколько полей, вы можете просто приковать их оператор возврата с большим количеством логических операторов.

+0

, по сути, вы могли бы его убрать с помощью '.reduce()' – ekkis

+0

, однако '.localCompare()' возвращает -1, 0, 1, поэтому я не думаю, что ваше решение будет работать как | | подходит для логических значений – ekkis

+3

@ekkis, и 1 и -1 являются «правдивыми», поэтому это очень элегантное решение. Я только что сделал это: 'sortItems = (a, b) => (a.distance - b.distance) || (a.name - b.name); ' и он работает как прелесть для моих нерасходованных потребностей. – bstst

Смежные вопросы