Monday, June 18, 2012

NSArray を NSSortDescriptor でソート

NSDictionary を詰め込んだ NSArray を NSDictionary のキーでソートしたい場合は NSSortDescriptor が便利です。

NSMutableArray *people = [[NSMutableArray alloc] init];

for (int i = 0; i < 5; i++) {

    NSMutableDictionary *person = [[NSMutableDictionary alloc] init];

    [person setValue:[NSString stringWithFormat:@"person-%d", i]
              forKey:@"name"];

    int age = 20 + (rand() % 20);
    [person setValue:[NSNumber numberWithInt:age] forKey:@"age"];

    NSTimeInterval interval = -1 * (rand() % 10) * 86400;
    NSDate *createdAt = [NSDate dateWithTimeIntervalSinceNow:interval];
    [person setValue:createdAt forKey:@"createdAt"];
            
    [people addObject:person];
}

NSLog(@"%@", people);

上記のコードで、以下のような NSDictionary を詰め込んだ NSArray が出来たとします。

(
        {
        age = 27;
        createdAt = "2012-06-09 10:43:55 +0000";
        name = "person-0";
    },
        {
        age = 33;
        createdAt = "2012-06-10 10:43:55 +0000";
        name = "person-1";
    },
        {
        age = 30;
        createdAt = "2012-06-16 10:43:55 +0000";
        name = "person-2";
    },
        {
        age = 24;
        createdAt = "2012-06-10 10:43:55 +0000";
        name = "person-3";
    },
        {
        age = 23;
        createdAt = "2012-06-09 10:43:55 +0000";
        name = "person-4";
    }
)

NSSortDescriptor を使ってソートしてみます。

NSSortDescriptor *ageAsc = [[[NSSortDescriptor alloc] initWithKey:@"age" ascending:YES] autorelease];
NSSortDescriptor *createdAtDesc = [[[NSSortDescriptor alloc] initWithKey:@"createdAt" ascending:NO] autorelease];
NSArray *descriptors = [NSArray arrayWithObjects:createdAtDesc, ageAsc, nil];
[people sortUsingDescriptors:descriptors];

NSLog(@"%@", people);

以下のようになります。複数のソートキーを指定できるため、SQL の ORDER BY っぽい感覚で使えます。

(
        {
        age = 30;
        createdAt = "2012-06-16 10:43:55 +0000";
        name = "person-2";
    },
        {
        age = 24;
        createdAt = "2012-06-10 10:43:55 +0000";
        name = "person-3";
    },
        {
        age = 33;
        createdAt = "2012-06-10 10:43:55 +0000";
        name = "person-1";
    },
        {
        age = 23;
        createdAt = "2012-06-09 10:43:55 +0000";
        name = "person-4";
    },
        {
        age = 27;
        createdAt = "2012-06-09 10:43:55 +0000";
        name = "person-0";
    }
)