Sortir NSArray string atau objek tanggal

86

Saya memiliki NSArrayyang berisi string tanggal (yaitu NSString) seperti ini: "Kam, 21 Mei 09 19:10:09 -0700"

Saya perlu mengurutkan NSArrayberdasarkan tanggal. Saya berpikir untuk mengonversi string tanggal ke NSDateobjek terlebih dahulu, tetapi terjebak di sana tentang cara mengurutkan berdasarkan NSDateobjek.

Terima kasih.

layanan pos14
sumber
Ditandai ulang karena ini terkait dengan kerangka Foundation, dan tidak khusus untuk iPhone.
Quinn Taylor

Jawaban:

110

Simpan tanggal sebagai NSDateobjek dalam NS (Mutable) Array, lalu gunakan -[NSArray sortedArrayUsingSelector:atau -[NSMutableArray sortUsingSelector:]dan berikan @selector(compare:)sebagai parameter. The -[NSDate compare:]Metode akan memesan tanggal di urutan menaik untuk Anda. Ini lebih sederhana daripada membuat NSSortDescriptor, dan jauh lebih sederhana daripada menulis fungsi perbandingan Anda sendiri. ( NSDateobjek tahu cara membandingkan dirinya satu sama lain setidaknya seefisien yang bisa kami capai dengan kode kustom.)

Quinn Taylor
sumber
11
Tidak jelas apakah pertanyaan asli menanyakan tentang pengurutan larik tanggal, atau pengurutan larik objek yang memiliki bidang tanggal. Ini adalah pendekatan termudah jika yang pertama, tetapi jika yang terakhir, NSSortDescriptor adalah cara yang tepat.
smorgan
@smorgan bagaimana NSSortDescriptor menangani tanggal nihil?
Abu
Terima kasih atas bantuan Anda, saya pikir kita harus membaca lebih lanjut di Apple Docs tetapi tampaknya sangat membosankan, sampai Anda menggunakannya.
Abo3atef
1
Bisakah Anda menunjukkan ini dalam kode cuplikan sebagai contoh? Terima kasih sebelumnya.
uplearnedu.com
115

Jika saya memiliki NSMutableArrayobjek dengan bidang "beginDate" tipe NSDatesaya menggunakan NSSortDescriptorseperti di bawah ini:

NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"beginDate" ascending:TRUE];
[myMutableArray sortUsingDescriptors:[NSArray arrayWithObject:sortDescriptor]];
[sortDescriptor release];
vinzenzweber.dll
sumber
3
Saya tahu banyak waktu berlalu (ketika jawaban sebelumnya diterima, mungkin belum ada NSSortDescriptor), tetapi untuk penggunaan di masa mendatang, jawaban ini harus menjadi jawaban yang tepat.
Vive
1
Ini adalah solusi yang luar biasa. memecahkan masalah saya dalam beberapa baris kode. Thanx a ton @vinzenzweber
Pratyusha Terli
1
Sungguh ... Saya benar-benar terkejut ini berhasil pada putaran pertama! Saya pikir initWithKey dicadangkan untuk kamus di mana kuncinya didefinisikan, tetapi yang perlu Anda lakukan hanyalah mereferensikan properti dalam array objek? Biarkan cahaya bersinar vinzenzweberskavitchski !!
whyoz
NSSortDescriptor telah ada sejak OS X 10.3, pada akhir 2003. Ini adalah skenario yang sedikit berbeda, di mana tanggal adalah kolom di objek lain. Dengan API yang lebih modern, Anda mungkin juga menggunakan -[NSMutableArray sortUsingComparator:](10.6+) dan meneruskan blok yang mengembalikan hasil pemanggilan -compare:pada dua bidang. Mungkin akan lebih cepat daripada memanggil -valueForKey:setiap objek. Anda bahkan dapat menggunakan -sortWithOptions:usingComparator:dan meneruskan opsi untuk mengurutkan secara bersamaan juga.
Quinn Taylor
bagaimana NSSortDescriptor di atas menangani tanggal nihil? Apakah kita perlu memberi tahu para desecriptor apa yang harus dilakukan dengan mereka jika demikian, bagaimana?
Abu
17

Anda juga dapat menggunakan sesuatu seperti berikut:

//Sort the array of items by  date
    [self.items sortUsingComparator:^NSComparisonResult(id obj1, id obj2){
        return [obj2.date compare:obj1.date];
    }];

Tapi ini mengasumsikan bahwa tanggal disimpan sebagai NSDateaNString , yang seharusnya tidak ada masalah untuk dibuat / dilakukan. Lebih disukai, saya sarankan juga menyimpan data dalam format mentahnya. Mempermudah manipulasi dalam situasi seperti ini.

TheCodingArt
sumber
9

Anda dapat menggunakan blok untuk mengurutkan di tempat:

sortedDatesArray = [[unsortedDatesArray sortedArrayUsingComparator: ^(id a, id b) {
    NSDate *d1 = [NSDate dateWithString: s1];
    NSDate *d2 = [NSDate dateWithString: s2];
    return [d1 compare: d2];
}];

Saya sarankan Anda mengonversi semua string Anda ke tanggal sebelum menyortir untuk tidak melakukan konversi lebih banyak daripada item tanggal. Algoritme pengurutan apa pun akan memberi Anda lebih banyak string untuk konversi saat ini daripada jumlah item dalam array (terkadang jauh lebih banyak)

sedikit lebih banyak tentang penyortiran blok: http://sokol8.blogspot.com/2011/04/sorting-nsarray-with-blocks.html

Kostiantyn Sokolinskyi
sumber
Ini adalah varian dari ide sub-optimal yang sama yang disajikan oleh @notoop. Bagaimanapun, mengonversi ke NSDate terlebih dahulu jelas merupakan cara yang harus ditempuh.
Quinn Taylor
Dia pada dasarnya hanya meletakkan jawaban saya dengan jawaban @notoop ..... cukup tidak perlu untuk menggandakan posting itu jika Anda bertanya kepada saya ....
TheCodingArt
Ini jauh lebih lambat daripada mengurai string tanggal ke dalam array NSDate dan kemudian mengurutkan array NSDate, karena akan ada 2 * (n - 1) kali parsing string ekstra. Parsing string umumnya merupakan pekerjaan berat di CPU.
CarlLee
5

Apa yang berhasil dalam kasus saya adalah sebagai berikut:

    NSArray * aUnsorted = [dataToDb allKeys];
    NSArray * arrKeys = [aUnsorted sortArrayUsingComparator: ^ NSComparisonResult (id obj1, id obj2) {
        NSDateFormatter * df = [[NSDateFormatter alokasi] init];
        [df setDateFormat: @ "dd-MM-yyyy"];
        NSDate * d1 = [df dateFromString: (NSString *) obj1];
        NSDate * d2 = [df dateFromString: (NSString *) obj2];
        kembali [d1 bandingkan: d2];
    }];

Saya punya kamus, di mana semua kunci di mana tanggal dalam format dd-MM-yyyy. Dan allKeys mengembalikan kunci kamus tanpa disortir, dan saya ingin menyajikan data dalam urutan kronologis.

Javier Calatrava Llavería
sumber
5

Anda bisa menggunakan sortedArrayUsingFunction:context:. Berikut ini contohnya:

NSComparisonResult dateSort(NSString *s1, NSString *s2, void *context) {
    NSDate *d1 = [NSDate dateWithString:s1];
    NSDate *d2 = [NSDate dateWithString:s2];
    return [d1 compare:d2];
}

NSArray *sorted = [unsorted sortedArrayUsingFunction:dateSort context:nil];

Saat menggunakan NSMutableArray, Anda bisa menggunakan sortArrayUsingFunction:context:.

notnoop
sumber
9
Ini adalah ide yang buruk - fungsi perbandingan harus cepat, dan tidak harus membuat objek NSDate dari string untuk setiap perbandingan. Jika Anda sudah menggunakan - [NSDate bandingkan:], cukup simpan tanggal dalam larik dan gunakan -sortedArrayUsingSelector: secara langsung.
Quinn Taylor
Saya rasa ini adalah solusi yang baik jika Anda menyortir objek yang sudah memiliki bidang NSDate sekalipun. Tidak?
GnarlyDog
1
Jika array sudah berisi NSDateobjek, Anda dapat menggunakan jawaban saya di atas, atau bahkan menggunakan -[NSMutableArray sortUsingComparator:], yang telah ditambahkan di 10.6.
Quinn Taylor
Jika Anda menggunakan larik kamus di mana terdapat objek nilai kunci untuk tanggal sebagai NSString bersama dengan beberapa objek nilai kunci lainnya, maka solusi ini adalah yang terbaik sejauh ini. Hanya perlu sedikit modifikasi di dalam fungsi dateSort. Jempolan! :)
Erfan
4

Setelah Anda memiliki NSDate, Anda dapat membuat NSSortDescriptordengan initWithKey:ascending:dan kemudian digunakan sortedArrayUsingDescriptors:untuk melakukan penyortiran.

smorgan
sumber
Pendekatan ini akan berhasil, tetapi menggunakan -sortedArrayUsingSelector: sedikit lebih sederhana dan tidak memerlukan pembuatan objek tambahan.
Quinn Taylor
Sebelum pengeditan, pertanyaannya menyebutkan "kunci 'tanggal'", jadi saya berasumsi bahwa ini sebenarnya adalah larik objek / kamus yang memiliki tanggal sebagai satu bidang, bukan larik tanggal mentah. Dalam hal ini sortArrayUsingSelector: lebih kompleks, karena memerlukan penulisan rutin pengurutan khusus untuk melakukan pencarian.
smorgan
Ya, maaf atas kebingungan apa pun - Saya membersihkan referensi itu karena dia hanya mengatakan bahwa dia menyimpan arraynya dengan kunci 'tanggal', dan saya menyadari itu hanya membuat pertanyaannya lebih membingungkan. Anda pasti benar tentang kompleksitas relatif mengingat struktur data yang lebih kompleks.
Quinn Taylor
2

Swift 3.0.0

myMutableArray = myMutableArray.sorted(by: { $0.date.compare($1.date) == ComparisonResult.orderedAscending })
Abhishek Jain
sumber
1

Ubah ini

NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"beginDate" ascending:TRUE];
[myMutableArray sortUsingDescriptors:[NSArray arrayWithObject:sortDescriptor]];
[sortDescriptor release];

Untuk

NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"Date" ascending:TRUE];
[myMutableArray sortUsingDescriptors:[NSArray arrayWithObject:sortDescriptor]];
[sortDescriptor release];

Ubah saja KUNCI: itu harus Dateselalu

pengguna2339385
sumber