2013年9月3日火曜日

sortUsingComparatorでソートをカスタマイズ

以下のようなCatクラスがあったとして、NSMutableArrayに格納してソートしてみましょう。
@interface Cat : NSObject

@property (nonatomic,strong)NSString *name;
@property (nonatomic,assign)int age;

@end

@implementation Cat

- (NSString*)description
{
    return [NSString stringWithFormat:@"< Cat: age=%d , name=%@ >"
                ,self.age,self.name];
}

@end


サンプルとして、配列は以下のように作りました。
NSMutableArray *array = [NSMutableArray arrayWithCapacity:4];
Cat *cat = [[Cat alloc] init];
cat.name = @"Toro";
cat.age = 5;
[array addObject:cat];
        
cat = [[Cat alloc] init];
cat.name = @"Tama";
cat.age = 5;
[array addObject:cat];
        
cat = [[Cat alloc] init];
cat.name = @"Doraemon";
cat.age = 3;
[array addObject:cat];
        
cat = [[Cat alloc] init];
cat.name = @"Dorami";
cat.age = 1;
[array addObject:cat];
        
NSLog(@"array = %@",array);
ログ出力の結果。
配列に格納した順番に、Catが表示されているのが分かります。
2013-09-03 11:59:41.774 SortTest[440:c07] array = (
    "< Cat: age=5 , name=Toro >",
    "< Cat: age=5 , name=Tama >",
    "< Cat: age=3 , name=Doraemon >",
    "< Cat: age=1 , name=Dorami >"
)

これを年齢(age)を昇順にソートして、年齢が同じなら名前(name)を昇順にソートするようにしてみます。
NSMutableArrayのsortUsingComparator:メソッドを使用してやってみます。
[array sortUsingComparator:^NSComparisonResult(Cat *cat1, Cat *cat2) {
    if (cat1.age<cat2.age) {
        return NSOrderedAscending;
    }
    if (cat1.age>cat2.age) {
        return NSOrderedDescending;
    }
    return [cat1.name compare:cat2.name];
}];
ブロックの中で2つの要素を比較するロジックを記述し、NSComparisonResultを返します。

まず、cat1とcat2のageを比較して、cat1.ageの方が小さければ、NSOrderedAscendingを返します。Ascendingは昇順を意味します。
if (cat1.age<cat2.age) {
    return NSOrderedAscending;  // 昇順を返す
}
対して、cat2.ageの方が小さければ、降順を表すNSOrderedDescendingを返してやります。
if (cat1.age>cat2.age) {
    return NSOrderedDescending;  // 降順を返す
}
これらどちらでも無いという事は、2つのageは同じであるという事なので、今度は名前を比較します。

name(NSString)の比較にはcompare:メソッドが用意されているので、こちらを使うことにします。 compare:メソッドはNSComparisonResultを返すので、結果をそのままブロックの返り値に利用できます。

上記ソートを実行したあとにarrayをログ出力すると、以下のようになりました。
ソート前のログと較べてみて下さい。
2013-09-03 11:59:41.775 SortTest[440:c07] array = (
    "< Cat: age=1 , name=Dorami >",
    "< Cat: age=3 , name=Doraemon >",
    "< Cat: age=5 , name=Tama >",
    "< Cat: age=5 , name=Toro >"
)

よくある問題ですが、年齢を昇順ではなく、降順にするにはどうするのでしょうか?
ageを比較した結果のNSOrderedAscendingとNSOrderedDescendingを入れ替えてやります。
[array sortUsingComparator:^NSComparisonResult(Cat *cat1, Cat *cat2) {
    if (cat1.age<cat2.age) {
        return NSOrderedDescending;  // 降順
    }
    if (cat1.age>cat2.age) {
        return NSOrderedAscending;    // 昇順
    }
    return [cat1.name compare:cat2.name];
}];
ソート後のログ出力は、以下のようになりました。
当然ですが、名前のソートは昇順のままです。降順にしたい場合は、各自チャレンジして下さい。
2013-09-03 12:24:24.789 SortTest[510:c07] array = (
    "< Cat: age=5 , name=Tama >",
    "< Cat: age=5 , name=Toro >",
    "< Cat: age=3 , name=Doraemon >",
    "< Cat: age=1 , name=Dorami >"
)

関連記事

0 件のコメント:

コメントを投稿

Related Posts Plugin for WordPress, Blogger...