Tarih dizilerinin veya nesnelerin NSArrayını sırala


86

Şuna benzer NSArraytarih dizeleri (yani NSString) içeren bir tane var : "Per, 21 Mayıs 09 19:10:09 -0700"

NSArrayTarihe göre sıralamam gerekiyor . NSDateÖnce tarih dizesini bir nesneye dönüştürmeyi düşündüm , ancak NSDatenesneye göre nasıl sıralayacağım konusunda orada takılıp kaldım .

Teşekkürler.


Bu, iPhone'a özgü olmadığı ve Temel çerçevesiyle ilgili olduğu için yeniden etiketlendi.
Quinn Taylor

Yanıtlar:


110

Tarihleri NSDatebir NS (Değişken) Dizisinde nesneler olarak saklayın, ardından -[NSArray sortedArrayUsingSelector:veya kullanın -[NSMutableArray sortUsingSelector:]ve @selector(compare:)parametre olarak iletin. -[NSDate compare:]Yöntem sizin için küçükten büyüğe tarihleri sıralar. Bu, bir oluşturmaktan NSSortDescriptorve kendi karşılaştırma işlevinizi yazmaktan çok daha basittir. ( NSDatenesneler, kendilerini en az özel kodla başarmayı umduğumuz kadar verimli bir şekilde birbirleriyle nasıl karşılaştıracaklarını bilirler.)


11
Orijinal sorunun bir tarih dizisini mi yoksa bir tarih alanı olan bir dizi nesneyi sıralamak mı sorduğu belli değil. İlki ise en kolay yaklaşım budur, ancak ikincisi ise NSSortDescriptor gitmenin yoludur.
smorgan

@smorgan NSSortDescriptor sıfır tarihleri ​​nasıl işler?
Kül

Yardımınız için teşekkürler, Apple Docs'ta daha fazla okumamız gerektiğini düşünüyorum ama kullanana kadar çok sıkıcı görünüyor.
Abo3atef

1
Bunu bir örnek olarak bir ön bilgi kodunda gösterebilir misiniz? Şimdiden teşekkürler.
uplearnedu.com

115

NSMutableArray"BeginDate" türünde bir alana sahip nesnelerim varsa , aşağıdaki gibi NSDatebir kullanıyorum NSSortDescriptor:

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

3
Çok zaman geçtiğini biliyorum (önceki cevap kabul edildiğinde henüz NSSortDescriptor olamazdı), ancak ileride kullanmak için bu doğru cevap olmalıdır.
Vive

1
Bu harika bir çözüm. sorunumu birkaç satır kodla
çözdüm. thhanx

1
Gerçekten ... Aslında bu ilk çalıştırmada işe yaradı! İnitWithKey'in anahtarın tanımlandığı sözlükler için ayrıldığını düşündüm, ancak yapmanız gereken tek şey bir dizi nesnede bir özelliğe başvurmak mı? Bırakın ışık vinzenzweberskavitchski parlasın !!
whyoz

NSSortDescriptor 2003'ün sonlarında OS X 10.3'ten beri var. Bu biraz farklı bir senaryodur, burada tarih başka bir nesnede bir alan. Daha da modern API ile, -[NSMutableArray sortUsingComparator:](10.6+) kullanabilir -compare:ve iki alanda arama sonucunu döndüren bir bloğu geçebilirsiniz . Muhtemelen -valueForKey:her nesneyi aramaktan daha hızlı olacaktır . -sortWithOptions:usingComparator:Eşzamanlı olarak sıralamak için seçenekleri bile kullanabilir ve geçirebilirsiniz.
Quinn Taylor

Yukarıdaki NSSortDescriptor sıfır tarihleri ​​nasıl işler? Çözücüye, eğer öyleyse, onlarla ne yapacağımızı söylememiz gerekiyor mu, nasıl?
Kül

17

Aşağıdaki gibi bir şey de kullanabilirsiniz:

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

Ancak bu, tarihin daha NSDateziyade a olarak kaydedildiğini varsayarNString , bu da yapmak / yapmak için sorun olmamalıdır. Tercihen veriyi ham formatında saklamanızı tavsiye ederim. Bu gibi durumlarda manipüle etmeyi kolaylaştırır.


9

Yerinde sıralamak için blokları kullanabilirsiniz:

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

Tarih öğelerinden daha fazla dönüştürme yapmamak için tüm dizelerinizi sıralamadan önce tarihlere dönüştürmenizi öneririm. Herhangi bir sıralama algoritması, dizideki öğelerin sayısından (bazen önemli ölçüde daha fazla) bugüne kadarki dönüşümler için size daha fazla dizi verecektir.

blok sıralama hakkında biraz daha fazla bilgi: http://sokol8.blogspot.com/2011/04/sorting-nsarray-with-blocks.html


Bu, @notoop tarafından sunulan aynı ideal altı fikrin bir çeşididir. Her durumda, önce NSDate'e dönüştürmek kesinlikle gidilecek yoldur.
Quinn Taylor

Temelde cevabımı @ notoop'un cevabına koydu ..... bana sorarsanız bunları ikiye katlamak oldukça gereksiz ....
TheCodingArt

Bu, tarih dizelerini NSDate dizisine ayrıştırmaktan ve NSDate dizisini sıralamaktan çok daha yavaştır, çünkü dizenin 2 * (n - 1) katı ek ayrıştırılması olacaktır. Dizeleri ayrıştırmak genellikle CPU üzerinde ağır bir iştir.
CarlLee

5

Benim durumumda işe yarayan şey şuydu:

    NSArray * aUnsorted = [dataToDb allKeys];
    NSArray * arrKeys = [aUnsorted sıralanmışArrayUsingComparator: ^ NSComparisonResult (id obj1, id obj2) {
        NSDateFormatter * df = [[NSDateFormatter tahsisi] init];
        [df setDateFormat: @ "gg-AA-yyyy"];
        NSDate * d1 = [df dateFromString: (NSString *) obj1];
        NSDate * d2 = [df dateFromString: (NSString *) obj2];
        dönüş [d1 karşılaştır: d2];
    }];

Tarihlerin gg-AA-yyyy biçiminde olduğu tüm anahtarların bulunduğu bir sözlüğüm vardı. Ve allKeys, sözlük anahtarlarını sıralanmamış olarak döndürüyor ve verileri kronolojik sırayla sunmak istedim.


5

Kullanabilirsiniz sortedArrayUsingFunction:context:. İşte bir örnek:

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

A kullanırken NSMutableArray, sortArrayUsingFunction:context:bunun yerine kullanabilirsiniz .


9
Bu kötü bir fikir - bir karşılaştırma işlevi hızlı olmalı ve her karşılaştırma için dizelerden NSDate nesneleri oluşturmamalıdır. Zaten - [NSDate Compare:] kullanıyorsanız, tarihleri ​​dizide saklayın ve -sortedArrayUsingSelector: öğesini doğrudan kullanın.
Quinn Taylor

Halihazırda bir NSDate alanı olan nesneleri sıralıyorsanız, bunun iyi bir çözüm olduğunu düşünüyorum. Hayır?
GnarlyDog

1
Dizi zaten NSDatenesneler içeriyorsa , yukarıdaki cevabımı kullanabilir veya -[NSMutableArray sortUsingComparator:]10.6'da eklenmiş olanı kullanabilirsiniz .
Quinn Taylor

NSString olarak tarih için bir anahtar-değer nesnesinin yanı sıra diğer bazı anahtar-değer nesnelerinin bulunduğu bir sözlük dizisi kullanıyorsanız, bu çözüm şimdiye kadarki en iyisidir. DateSort işlevi içinde biraz değişiklik yapmanız yeterlidir. Başparmak havaya! :)
Erfan

4

Bir kez sahip NSDateolduğunuzda, bir NSSortDescriptorile oluşturabilir initWithKey:ascending:ve ardından sortedArrayUsingDescriptors:sıralamayı yapmak için kullanabilirsiniz .


Bu yaklaşım işe yarayacak, ancak -sortedArrayUsingSelector kullanmak biraz daha basittir ve fazladan bir nesne oluşturmayı gerektirmez.
Quinn Taylor

Ön düzenleme, soru "bir 'tarih' anahtarı" ndan bahsediyordu, bu yüzden bunun gerçekten bir ham tarih dizisi değil, bir alan olarak bir tarihi olan bir nesne / sözlük dizisi olduğunu varsaydım. Bu durumda, sortArrayUsingSelector: aramayı yapmak için özel bir sıralama rutini yazmayı gerektirdiğinden daha karmaşıktır.
smorgan

Evet, herhangi bir karışıklık için özür dilerim - dizisini bir 'tarih' anahtarıyla sakladığını söylediği için bu referansı temizledim ve bunun soruyu daha kafa karıştırıcı hale getirdiğini fark ettim. Daha karmaşık bir veri yapısı verildiğinde göreceli karmaşıklık konusunda kesinlikle haklısınız.
Quinn Taylor

2

Swift 3.0

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

1

Bunu değiştir

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

İçin

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

Sadece ANAHTARI değiştirin: Dateher zaman olmalıdır

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.