Urutkan array objek dengan kunci tunggal dengan nilai tanggal


257

Saya memiliki array objek dengan beberapa pasangan nilai kunci, dan saya perlu mengurutkannya berdasarkan 'updated_at':

[
    {
        "updated_at" : "2012-01-01T06:25:24Z",
        "foo" : "bar"
    },
    {
        "updated_at" : "2012-01-09T11:25:13Z",
        "foo" : "bar"
    },
    {
        "updated_at" : "2012-01-05T04:13:24Z",
        "foo" : "bar"
    }
]

Apa cara paling efisien untuk melakukannya?


@Topener Tautan itu sepertinya adalah pertanyaan tentang PHP
David Brainer

kesalahan saya .. tidak membacanya dengan benar
Rene Pot

Jawaban:


339

Anda bisa menggunakannya Array.sort.

Ini sebuah contoh:

var arr = [{
    "updated_at": "2012-01-01T06:25:24Z",
    "foo": "bar"
  },
  {
    "updated_at": "2012-01-09T11:25:13Z",
    "foo": "bar"
  },
  {
    "updated_at": "2012-01-05T04:13:24Z",
    "foo": "bar"
  }
]

arr.sort(function(a, b) {
  var keyA = new Date(a.updated_at),
    keyB = new Date(b.updated_at);
  // Compare the 2 dates
  if (keyA < keyB) return -1;
  if (keyA > keyB) return 1;
  return 0;
});

console.log(arr);


17
Tidak bisakah Anda menggunakan keyA - keyB(atau mungkin keyB - keyA)? Objek tanggal memiliki valueOf()metode.
soktinpk

mengembalikan a. updated_at <b. updated_at? 1: -1 bekerja untuk saya. Tidak perlu menguraikan format tanggal.
oliversisson

Kemampuan untuk melakukan a-bsangat penting jika Anda ingin menghindari kode panjang. Sementara kode panjang tidak selalu buruk dalam hal ini saya pikir verbositas membuatnya lebih sulit untuk dipahami. Saat ini saya menggunakan values.sort((a,b)=>a.attr-b.attr). Harus menulis 5 baris setiap kali Anda perlu mengurutkan array menjadi membosankan.
AnnanFay

Contoh ini tidak efektif dan melakukan banyak perhitungan yang tidak perlu. Sort dapat mengambil angka positif atau negatif sebagai hasil yang valid. Perhitungan ekstra Anda untuk memaksanya menjadi 1,0, -1 tidak diperlukan dan hanya menambahkan perhitungan ekstra per eksekusi.
Patrick W. McMahon

Terima kasih banyak
Andy

158

Saya sudah menjawab pertanyaan yang sangat mirip di sini: Fungsi sederhana untuk mengurutkan berbagai objek

Untuk pertanyaan itu saya membuat fungsi kecil ini yang mungkin melakukan apa yang Anda inginkan:

function sortByKey(array, key) {
    return array.sort(function(a, b) {
        var x = a[key]; var y = b[key];
        return ((x < y) ? -1 : ((x > y) ? 1 : 0));
    });
}

11
Dom

2
Bagaimana Anda membalikkan ini?

4
Untuk membuatnya case-insensitive, Anda bisa menambahkan .toLowerCase () ke variabel x dan y
Jacob van Lingen

4
Untuk membalikkan fungsi penyortiran seperti ini, cukup gandakan hasilnya dengan -1:)
Svish

5
Atau ambil saja output dan gunakan array = array.reverse()fungsinya.
Luke Stevenson

31

Metode Array.sort () mengurutkan elemen array di tempat dan mengembalikan array. Hati-hati dengan Array.sort () karena tidak dapat diubah . Untuk sortir immutable gunakan immutable-sort .

Metode ini adalah mengurutkan array menggunakan arus Anda updated_atdalam format ISO. Kami menggunakan new Data(iso_string).getTime()untuk mengubah waktu ISO ke cap waktu Unix. Stempel waktu Unix adalah angka yang bisa kita gunakan matematika sederhana. Kami kurangi cap waktu pertama dan kedua hasilnya adalah; jika stempel waktu pertama lebih besar dari yang kedua, angka pengembaliannya akan positif. Jika angka kedua lebih besar dari yang pertama nilai pengembaliannya akan negatif. Jika keduanya sama, pengembaliannya akan nol. Ini alines sempurna dengan nilai pengembalian yang diperlukan untuk fungsi inline.

Untuk ES6 :

arr.sort((a,b) => new Date(a.updated_at).getTime() - new Date(b.updated_at).getTime());

Untuk ES5 :

arr.sort(function(a,b){ 
 return new Date(a.updated_at).getTime() - new Date(b.updated_at).getTime();
});

Jika Anda mengubah updated_atmenjadi cap waktu unix, Anda dapat melakukan ini:

Untuk ES6 :

arr.sort((a,b) => a.updated_at - b.updated_at);

Untuk ES5 :

arr.sort(function(a,b){ 
 return a.updated_at - b.updated_at;
});

Pada saat posting ini, browser modern tidak mendukung ES6. Untuk menggunakan ES6 di browser modern, gunakan babel untuk mengubah kode menjadi ES5. Harapkan dukungan browser untuk ES6 dalam waktu dekat.

Array.sort () harus menerima nilai pengembalian salah satu dari 3 hasil yang mungkin:

  • Angka positif (item pertama> item kedua)
  • Angka negatif (item pertama <item kedua)
  • 0 jika kedua item sama

Perhatikan bahwa nilai kembali pada fungsi sebaris dapat berupa angka positif atau negatif. Array.Sort () tidak peduli berapa nomor pengembaliannya. Itu hanya peduli jika nilai kembali positif, negatif atau nol.

Untuk jenis Immutable: (contoh dalam ES6)

const sort = require('immutable-sort');
const array = [1, 5, 2, 4, 3];
const sortedArray = sort(array);

Anda juga dapat menulis seperti ini:

import sort from 'immutable-sort';
const array = [1, 5, 2, 4, 3];
const sortedArray = sort(array);

Impor-dari yang Anda lihat adalah cara baru untuk memasukkan javascript di ES6 dan membuat kode Anda terlihat sangat bersih. Favorit pribadi saya.

Sortir yang tidak berubah tidak mengubah array sumber, melainkan mengembalikan array baru. Menggunakan constdianjurkan pada data berubah.


19

Berikut ini adalah versi @David Brainer-Banker yang sedikit dimodifikasi yang mengurutkan secara abjad berdasarkan string, atau secara numerik dengan angka, dan memastikan bahwa kata-kata yang dimulai dengan huruf kapital tidak mengurutkan kata-kata di atas dimulai dengan huruf kecil (misalnya "apel, awal" akan ditampilkan dalam urutan itu).

function sortByKey(array, key) {
    return array.sort(function(a, b) {
        var x = a[key];
        var y = b[key];

        if (typeof x == "string")
        {
            x = (""+x).toLowerCase(); 
        }
        if (typeof y == "string")
        {
            y = (""+y).toLowerCase();
        }

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

3
Solusi yang diusulkan mungkin memberikan kesalahan jika [kunci] dan b [kunci] tidak keduanya. Saya sarankan untuk mengganti y = y.toLowerCase () dengan y = ("" + y) .toLowerCase ()
user8074

sort dapat menerima angka positif atau negatif sebagai pengembalian yang valid. Anda perhitungan ekstra untuk memaksanya menjadi 1,0, -1 tidak diperlukan. Anda lebih rumit dari nilai pengembalian yang sederhana. Yang terbaik adalah tidak menambahkan perhitungan tambahan yang tidak melakukan apa-apa.
Patrick W. McMahon


6

Dengan dukungan ES2015 dapat dilakukan dengan:

foo.sort((a, b) => a.updated_at < b.updated_at ? -1 : 1)

1
tidak perlu untuk inline jika ganti <dengan - dan hapus '? -1: 1 "Anda akan mendapatkan pengembalian yang valid. Contoh ini memindahkan item yang mungkin sama dan dengan demikian dapat memberikan hasil yang tidak terduga. Untuk item yang sama a harus dikembalikan.
Patrick W. McMahon

Terima kasih telah menjelaskan
ketahui

jika updated_at adalah waktu ISO, ini tidak akan berfungsi. Contoh ini mengasumsikan cap waktu Unix tetapi OP mem-posting data yang dalam format ISO. Jadi, Anda harus mengonversi ke cap waktu Unix untuk melakukan perbandingan. Ini dapat dilakukan dengan new Date(iso_str).getTime()ini akan mengembalikan cap waktu Unix.
Patrick W. McMahon

5

Data Diimpor

[
    {
        "gameStatus": "1",
        "userId": "c02cfb18-ae66-430b-9524-67d9dd8f6a50",
        "created_at": "2018-12-20 11:32:04"
    },
    {
        "gameStatus": "0",
        "userId": "c02cfb18-ae66-430b-9524-67d9dd8f6a50",
        "created_at": "2018-12-19 18:08:24"
    },
    {
        "gameStatus": "2",
        "userId": "c02cfb18-ae66-430b-9524-67d9dd8f6a50",
        "created_at": "2018-12-19 18:35:40"
    },
    {
        "gameStatus": "0",
        "userId": "c02cfb18-ae66-430b-9524-67d9dd8f6a50",
        "created_at": "2018-12-19 10:42:53"
    },
    {
        "gameStatus": "2",
        "userId": "c02cfb18-ae66-430b-9524-67d9dd8f6a50",
        "created_at": "2018-12-20 10:54:09"
    },
    {
        "gameStatus": "0",
        "userId": "1a2fefb0-5ae2-47eb-82ff-d1b2cc27875a",
        "created_at": "2018-12-19 18:46:22"
    },
    {
        "gameStatus": "1",
        "userId": "7118ed61-d8d9-4098-a81b-484158806d21",
        "created_at": "2018-12-20 10:50:48"
    }
]

UNTUK pesanan naik

arr.sort(function(a, b){
    var keyA = new Date(a.updated_at),
        keyB = new Date(b.updated_at);
    // Compare the 2 dates
    if(keyA < keyB) return -1;
    if(keyA > keyB) return 1;
    return 0;
});

Contoh untuk Asc Order

[
    {
        "gameStatus": "0",
        "userId": "c02cfb18-ae66-430b-9524-67d9dd8f6a50",
        "created_at": "2018-12-19 10:42:53"
    },
    {
        "gameStatus": "0",
        "userId": "c02cfb18-ae66-430b-9524-67d9dd8f6a50",
        "created_at": "2018-12-19 18:08:24"
    },
    {
        "gameStatus": "2",
        "userId": "c02cfb18-ae66-430b-9524-67d9dd8f6a50",
        "created_at": "2018-12-19 18:35:40"
    },
    {
        "gameStatus": "0",
        "userId": "1a2fefb0-5ae2-47eb-82ff-d1b2cc27875a",
        "created_at": "2018-12-19 18:46:22"
    },
    {
        "gameStatus": "1",
        "userId": "7118ed61-d8d9-4098-a81b-484158806d21",
        "created_at": "2018-12-20 10:50:48"
    },
    {
        "gameStatus": "2",
        "userId": "c02cfb18-ae66-430b-9524-67d9dd8f6a50",
        "created_at": "2018-12-20 10:54:09"
    },
    {
        "gameStatus": "1",
        "userId": "c02cfb18-ae66-430b-9524-67d9dd8f6a50",
        "created_at": "2018-12-20 11:32:04"
    }
]

UNTUK pesanan menurun

arr.sort(function(a, b){
    var keyA = new Date(a.updated_at),
        keyB = new Date(b.updated_at);
    // Compare the 2 dates
    if(keyA > keyB) return -1;
    if(keyA < keyB) return 1;
    return 0;
});

Contoh untuk Desc Order

[
    {
        "gameStatus": "1",
        "userId": "c02cfb18-ae66-430b-9524-67d9dd8f6a50",
        "created_at": "2018-12-20 11:32:04"
    },
    {
        "gameStatus": "2",
        "userId": "c02cfb18-ae66-430b-9524-67d9dd8f6a50",
        "created_at": "2018-12-20 10:54:09"
    },
    {
        "gameStatus": "1",
        "userId": "7118ed61-d8d9-4098-a81b-484158806d21",
        "created_at": "2018-12-20 10:50:48"
    },
    {
        "gameStatus": "0",
        "userId": "1a2fefb0-5ae2-47eb-82ff-d1b2cc27875a",
        "created_at": "2018-12-19 18:46:22"
    },
    {
        "gameStatus": "2",
        "userId": "c02cfb18-ae66-430b-9524-67d9dd8f6a50",
        "created_at": "2018-12-19 18:35:40"
    },
    {
        "gameStatus": "0",
        "userId": "c02cfb18-ae66-430b-9524-67d9dd8f6a50",
        "created_at": "2018-12-19 18:08:24"
    },
    {
        "gameStatus": "0",
        "userId": "c02cfb18-ae66-430b-9524-67d9dd8f6a50",
        "created_at": "2018-12-19 10:42:53"
    }
]

3

Seperti ini menyatakan jawaban ini, Anda dapat menggunakan Array.sort.

arr.sort(function(a,b){return new Date(a.updated_at) - new Date(b.updated_at)})

arr = [
    {
        "updated_at" : "2012-01-01T06:25:24Z",
        "foo" : "bar"
    },
    {
        "updated_at" : "2012-01-09T11:25:13Z",
        "foo" : "bar"
    },
    {
        "updated_at" : "2012-01-05T04:13:24Z",
        "foo" : "bar"
    }
];
arr.sort(function(a,b){return new Date(a.updated_at) - new Date(b.updated_at)});
console.log(arr);


2

Hanya cara lain yang lebih matematis dalam melakukan hal yang sama tetapi lebih pendek :

arr.sort(function(a, b){
    var diff = new Date(a.updated_at) - new Date(b.updated_at);
    return diff/(Math.abs(diff)||1);
});

atau dengan gaya panah lambda yang apik:

arr.sort((a, b) => {
    var diff = new Date(a.updated_at) - new Date(b.updated_at);
    return diff/(Math.abs(diff)||1);
});

Metode ini dapat dilakukan dengan input numerik apa pun


jawaban underated
two7s_clash


2

Saya telah membuat fungsi penyortiran dalam naskah yang dapat kita gunakan untuk mencari string, tanggal dan angka dalam array objek. Itu juga dapat mengurutkan pada beberapa bidang.

export type SortType = 'string' | 'number' | 'date';
export type SortingOrder = 'asc' | 'desc';

export interface SortOptions {
  sortByKey: string;
  sortType?: SortType;
  sortingOrder?: SortingOrder;
}


class CustomSorting {
    static sortArrayOfObjects(fields: SortOptions[] = [{sortByKey: 'value', sortType: 'string', sortingOrder: 'desc'}]) {
        return (a, b) => fields
          .map((field) => {
            if (!a[field.sortByKey] || !b[field.sortByKey]) {
              return 0;
            }

            const direction = field.sortingOrder === 'asc' ? 1 : -1;

            let firstValue;
            let secondValue;

            if (field.sortType === 'string') {
              firstValue = a[field.sortByKey].toUpperCase();
              secondValue = b[field.sortByKey].toUpperCase();
            } else if (field.sortType === 'number') {
              firstValue = parseInt(a[field.sortByKey], 10);
              secondValue = parseInt(b[field.sortByKey], 10);
            } else if (field.sortType === 'date') {
              firstValue = new Date(a[field.sortByKey]);
              secondValue = new Date(b[field.sortByKey]);
            }
            return firstValue > secondValue ? direction : firstValue < secondValue ? -(direction) : 0;

          })
          .reduce((pos, neg) => pos ? pos : neg, 0);
      }
    }
}

Pemakaian:

const sortOptions = [{
      sortByKey: 'anyKey',
      sortType: 'string',
      sortingOrder: 'asc',
    }];

arrayOfObjects.sort(CustomSorting.sortArrayOfObjects(sortOptions));

1

Menyortir menurut tanggal yang diformat ISO bisa mahal, kecuali jika Anda membatasi klien untuk browser terbaru dan terbaik, yang dapat membuat cap waktu yang benar dengan Date-parsing the string.

Jika Anda yakin dengan input Anda, dan Anda tahu itu akan selalu yyyy-mm-ddThh: mm: ss dan GMT (Z) Anda dapat mengekstraksi digit dari setiap anggota dan membandingkannya seperti bilangan bulat

array.sort(function(a,b){
    return a.updated_at.replace(/\D+/g,'')-b.updated_at.replace(/\D+/g,'');
});

Jika tanggal dapat diformat secara berbeda, Anda mungkin perlu menambahkan sesuatu untuk orang-orang dengan tantangan iso:

Date.fromISO: function(s){
    var day, tz,
    rx=/^(\d{4}\-\d\d\-\d\d([tT ][\d:\.]*)?)([zZ]|([+\-])(\d\d):(\d\d))?$/,
    p= rx.exec(s) || [];
    if(p[1]){
        day= p[1].split(/\D/).map(function(itm){
            return parseInt(itm, 10) || 0;
        });
        day[1]-= 1;
        day= new Date(Date.UTC.apply(Date, day));
        if(!day.getDate()) return NaN;
        if(p[5]){
            tz= (parseInt(p[5], 10)*60);
            if(p[6]) tz+= parseInt(p[6], 10);
            if(p[4]== '+') tz*= -1;
            if(tz) day.setUTCMinutes(day.getUTCMinutes()+ tz);
        }
        return day;
    }
    return NaN;
}
if(!Array.prototype.map){
    Array.prototype.map= function(fun, scope){
        var T= this, L= T.length, A= Array(L), i= 0;
        if(typeof fun== 'function'){
            while(i< L){
                if(i in T){
                    A[i]= fun.call(scope, T[i], i, T);
                }
                ++i;
            }
            return A;
        }
    }
}
}

2
Tidak bisakah Anda menggunakan saja Date.parse?
Rocket Hazmat

1

Untuk kelengkapan di sini adalah implementasi generik pendek yang mungkin dari sortBy:

function sortBy(list, keyFunc) {
  return list.sort((a,b) => keyFunc(a) - keyFunc(b));
}

sortBy([{"key": 2}, {"key": 1}], o => o["key"])

Perhatikan bahwa ini menggunakan metode susunan array yang mengurutkan di tempat. untuk salinan Anda dapat menggunakan arr.concat () atau arr.slice (0) atau metode serupa untuk membuat salinan.


1

Dengan ini kita bisa melewati fungsi kunci yang digunakan untuk menyortir

Array.prototype.sortBy = function(key_func, reverse=false){
    return this.sort( (a, b) => {
        var keyA = key_func(a),
            keyB = key_func(b);
        if(keyA < keyB) return reverse? 1: -1;
        if(keyA > keyB) return reverse? -1: 1;
        return 0;
    }); 
}

Lalu misalnya kalau sudah

var arr = [ {date: "01/12/00", balls: {red: "a8",  blue: 10}},
            {date: "12/13/05", balls: {red: "d6" , blue: 11}},
            {date: "03/02/04", balls: {red: "c4" , blue: 15}} ]

Kita bisa

arr.sortBy(el => el.balls.red)
/* would result in
[ {date: "01/12/00", balls: {red: "a8", blue: 10}},
  {date: "03/02/04", balls: {red: "c4", blue: 15}},
  {date: "12/13/05", balls: {red: "d6", blue: 11}} ]
*/

atau

arr.sortBy(el => new Date(el.date), true)   // second argument to reverse it
/* would result in
[ {date: "12/13/05", balls: {red: "d6", blue:11}},
  {date: "03/02/04", balls: {red: "c4", blue:15}},
  {date: "01/12/00", balls: {red: "a8", blue:10}} ]
*/

atau

arr.sortBy(el => el.balls.blue + parseInt(el.balls.red[1]))
/* would result in
[ {date: "12/13/05", balls: {red: "d6", blue:11}},    // red + blue= 17
  {date: "01/12/00", balls: {red: "a8", blue:10}},    // red + blue= 18
  {date: "03/02/04", balls: {red: "c4", blue:15}} ]   // red + blue= 19
*/

1

Anda bisa menggunakan pustaka utilitas Lodash untuk menyelesaikan masalah ini (pustaka yang cukup efisien):

const data = [{
    "updated_at": "2012-01-01T06:25:24Z",
    "foo": "bar"
  },
  {
    "updated_at": "2012-01-09T11:25:13Z",
    "foo": "bar"
  },
  {
    "updated_at": "2012-01-05T04:13:24Z",
    "foo": "bar"
  }
]

const ordered = _.orderBy(
  data,
  function(item) {
    return item.updated_at;
  }
);

console.log(ordered)
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.15/lodash.min.js"></script>

Anda dapat menemukan dokumentasi di sini: https://lodash.com/docs/4.17.15#orderBy


0

Anda dapat membuat penutupan dan mengopernya seperti itu di sini adalah contoh saya yang berfungsi

$.get('https://data.seattle.gov/resource/3k2p-39jp.json?$limit=10&$where=within_circle(incident_location, 47.594972, -122.331518, 1609.34)', 
  function(responce) {

    var filter = 'event_clearance_group', //sort by key group name
    data = responce; 

    var compare = function (filter) {
        return function (a,b) {
            var a = a[filter],
                b = b[filter];

            if (a < b) {
                return -1;
            } else if (a > b) {
                return 1;
            } else {
                return 0;
            }
        };
    };

    filter = compare(filter); //set filter

    console.log(data.sort(filter));
});

0
var months = [
    {
        "updated_at" : "2012-01-01T06:25:24Z",
        "foo" : "bar"
    },
    {
        "updated_at" : "2012-01-09T11:25:13Z",
        "foo" : "bar"
    },
    {
        "updated_at" : "2012-01-05T04:13:24Z",
        "foo" : "bar"
    }];
months.sort((a, b)=>{
    var keyA = new Date(a.updated_at),
        keyB = new Date(b.updated_at);
    // Compare the 2 dates
    if(keyA < keyB) return -1;
    if(keyA > keyB) return 1;
    return 0;
});
console.log(months);

0
  • Menggunakan Array.sort() untuk mengurutkan array
  • Clone array menggunakan operator spread ( ) untuk membuat fungsinya murni
  • Sortir menurut kunci yang diinginkan ( updated_at)
  • Konversi string tanggal menjadi objek tanggal
  • Array.sort() bekerja dengan mengurangi dua properti dari item saat ini dan berikutnya jika itu adalah nomor / objek di mana Anda dapat melakukan operasi aritmia
const input = [
  {
    updated_at: '2012-01-01T06:25:24Z',
    foo: 'bar',
  },
  {
    updated_at: '2012-01-09T11:25:13Z',
    foo: 'bar',
  },
  {
    updated_at: '2012-01-05T04:13:24Z',
    foo: 'bar',
  }
];

const sortByUpdatedAt = (items) => [...items].sort((itemA, itemB) => new Date(itemA.updated_at) - new Date(itemB.updated_at));

const output = sortByUpdatedAt(input);

console.log(input);
/*
[ { updated_at: '2012-01-01T06:25:24Z', foo: 'bar' }, 
  { updated_at: '2012-01-09T11:25:13Z', foo: 'bar' }, 
  { updated_at: '2012-01-05T04:13:24Z', foo: 'bar' } ]
*/
console.log(output)
/*
[ { updated_at: '2012-01-01T06:25:24Z', foo: 'bar' }, 
  { updated_at: '2012-01-05T04:13:24Z', foo: 'bar' }, 
  { updated_at: '2012-01-09T11:25:13Z', foo: 'bar' } ]
*/

0

Saya menghadapi hal yang sama, jadi saya menangani ini dengan alasan umum dan saya membangun fungsi untuk ini:

//example:
//array: [{name: 'idan', workerType: '3'}, {name: 'stas', workerType: '5'}, {name: 'kirill', workerType: '2'}]
//keyField: 'workerType'
// keysArray: ['4', '3', '2', '5', '6']
sortByArrayOfKeys = (array, keyField, keysArray) => {
    array.sort((a, b) => {
        const aIndex = keysArray.indexOf(a[keyField])
        const bIndex = keysArray.indexOf(b[keyField])
        if (aIndex < bIndex) return -1;
        if (aIndex > bIndex) return 1;
        return 0;
    })
}
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.