Array sortir Javascript dengan dua bidang

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

Jadi kode di atas mengurutkan array dengan gsize - dari terkecil ke terbesar. Ini bekerja dengan baik. Tetapi jika ukuran gsize sama, saya ingin mengurutkan berdasarkan cahaya.

Terima kasih.

Menandai
sumber
fungsi sortir bereaksi pada hasil positif, negatif atau nol. jadi Anda bisa menulis: "return aSize - bSize". itu akan menjadi kode yang lebih sederhana dan mudah dibaca.

Jawaban:

112
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;
    }
});
Chris Eberle
sumber
Untuk membuat lebih ringkas ini menggunakan panah sintaks, tanpa menggunakan teknik non-jelas ditunjukkan dalam beberapa jawaban lain: grouperArray.sort((a, b) => a.gsize == b.gsize ? a.glow - b.glow : a.gsize - b.gsize. Untuk membuat kode lebih mudah dipahami, kami terus menguji secara eksplisit ==.
ToolmakerSteve
171
grouperArray.sort(function (a, b) {   
    return a.gsize - b.gsize || a.glow - b.glow;
});

versi yang lebih pendek

anmorozov23
sumber
jalan pintas yang bagus! membantu saya menyusun solusi yang lebih kompleks bersama .. stackoverflow.com/questions/6101475/…
Joseph Poirier
3
Bagus dan bersih! Satu-satunya hal itu hanya berfungsi untuk angka.
Afanasii Kurakin
Bisakah Anda menjelaskan logikanya di sini?!. Ini berhasil bagi saya sort an array with a key's value firstdan kemudiansort the result with another key's value
KTM
1
@KTM Logikanya adalah sebagai berikut: jika kedua gsize sama, maka bagian pertama dari kondisi tersebut sama dengan 0, yang dianggap salah, dan bagian kedua dari ketentuan tersebut dijalankan.
Scalpweb
@Scalpweb Ya :) jadi ini berfungsi untuk mengurutkan array dengan sejumlah kunci satu per satu kan ?! Trik bagus
KTM
36
grouperArray.sort((a, b) => a.gsize - b.gsize || a.glow - b.glow);

Versi yang lebih pendek lagi menggunakan sintaks panah!

Vinorth
sumber
3
Paling ringkas dan bisa diperpanjang, sempurna!
Laurent
1
Lebih pendek lagi, keluarkan spasi:grouperArray.sort((a,b)=>a.gsize-b.gsize||a.glow-b.glow);
Captain Fantastic
jika Anda ingin memahami mengapa itu berhasil, Anda mungkin ingin melihat medium.com/@safareli/pss-ordering-is-a-monoid-61a4029387e
Safareli
14

Saya menyadari ini telah ditanyakan beberapa waktu lalu, tetapi saya pikir saya akan menambahkan solusi saya.

Fungsi ini menghasilkan metode pengurutan secara dinamis. cukup berikan setiap nama properti turunan yang dapat diurutkan, diawali dengan +/- untuk menunjukkan urutan naik atau turun. Sangat dapat digunakan kembali, dan tidak perlu mengetahui apa pun tentang struktur data yang telah Anda susun. Bisa dibuat bukti bodoh - tapi sepertinya tidak perlu.

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

contoh penggunaan:

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

ini akan mengurutkan itemsdengan yang terendah priceterlebih dahulu, dengan ikatan menuju ke item dengan yang tertinggi priority. ikatan selanjutnya diputus oleh item tersebutname

dimana item adalah array seperti:

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

demo langsung: http://gregtaff.com/misc/multi_field_sort/

EDIT: Memperbaiki masalah Chrome.

nihlton
sumber
Ini brilian
Azure
Jawaban jenius!
Marius
untuk skrip ketikan (untuk tidak mendapatkan error TS2554: Expected 0 arguments, but got ..) gunakan sintaks di sini: stackoverflow.com/a/4116634/5287221
Chananel P
6

Saya berharap operator terner((aSize < bSize) ? -1 : (aSize > bSize) ? 1 : 0;) membuat Anda bingung. Anda harus memeriksa tautan untuk memahaminya dengan lebih baik.

Sampai saat itu, berikut kode Anda meledak menjadi penuh 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;
    }
});
John Green
sumber
6

Berikut adalah implementasi untuk mereka yang mungkin menginginkan sesuatu yang lebih umum yang akan bekerja dengan sejumlah bidang.

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

}

Pada dasarnya, Anda dapat menentukan sejumlah nama properti / arah pengurutan:

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
The_Black_Smurf
sumber
3
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 );
});
silex.dll
sumber
3
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); }); 
Tim Williams
sumber
3

Berikut adalah implementasi yang menggunakan rekursi untuk mengurutkan berdasarkan sejumlah bidang pengurutan dari 1 hingga tak terbatas. Anda memberikan larik hasil yang merupakan larik objek hasil untuk diurutkan, dan larik sortir yang merupakan larik objek pengurutan yang mendefinisikan pengurutan. Setiap objek pengurutan harus memiliki kunci "pilih" untuk nama kunci yang diurutkan dan kunci "urutan" yang berupa string yang menunjukkan "naik" atau "turun".

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)
Benjamin Portman
sumber
2

Cara dinamis untuk melakukannya dengan tombol GANDA:

  • memfilter nilai unik dari setiap kolom / kunci pengurutan
  • mengatur atau membalikkannya
  • menambahkan bobot zeropad lebar untuk setiap objek berdasarkan nilai kunci indexOf (nilai)
  • mengurutkan menggunakan bobot caclutated

masukkan deskripsi gambar di sini

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

Menggunakan:

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

masukkan deskripsi gambar di sini

Leonardo Filipe
sumber
1

Ini yang saya gunakan

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

menggabungkan dua item sebagai string dan mereka akan diurutkan berdasarkan nilai string. Jika mau, Anda dapat membungkus _a dan _b dengan parseInt untuk membandingkannya sebagai angka jika Anda tahu bahwa keduanya akan berupa angka.

blockloop
sumber
1

Berikut adalah solusi untuk kasus ini, saat Anda memiliki kunci pengurutan prioritas, yang mungkin tidak ada di beberapa item tertentu, jadi Anda harus mengurutkan berdasarkan kunci cadangan.

Contoh data masukan ( id2 adalah kunci sortir prioritas):

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

Dan hasilnya harus:

[ { 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 } ]

Fungsi pembandingnya akan seperti:

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

PS Dalam kasus jika .id dari .id2 bisa nol, pertimbangkan untuk menggunakan typeof.

Deliaz
sumber
0
grouperArray.sort(
  function(a,b){return a.gsize == b.gsize ? a.glow - b.glow : a.gsize - b.gsize}
);
ic3b3rg
sumber
0
grouperArray.sort(function (a, b) {
    var aSize = a.gsize;
    var bSize = b.gsize;
    if (aSize !== aSize)
        return aSize - bSize;
    return a.glow - b.glow;
});

belum diuji, tapi saya pikir itu seharusnya berhasil.

Xander
sumber
0

Dalam kasus saya, saya mengurutkan daftar pemberitahuan berdasarkan param 'penting' dan menurut 'tanggal'

  • langkah 1: saya memfilter pemberitahuan dengan 'penting' dan tidak penting

    let importantNotifications = notifications.filter(
            (notification) => notification.isImportant);
    
      let unImportantNotifications = notifications.filter(
            (notification) => !notification.isImportant);
    
  • langkah 2: saya mengurutkannya berdasarkan tanggal

      sortByDate = (notifications) => {
      return notifications.sort((notificationOne, notificationTwo) => {
        return notificationOne.date - notificationTwo.date;
      });
    };
    
  • langkah 3: gabungkan mereka

    [
        ...this.sortByDate(importantNotifications),
        ...this.sortByDate(unImportantNotifications),
      ];
    
Phạm Hùng
sumber