使用两个特殊键对 NSmutablearray 进行排序

Sort NSmutablearray with two special keys

我有一个表视图,它的 header 存储在一个可变数组中,数组看起来像

(2005 fall, 2005 spring, 2007 summer...)

当我输出tableview时,我想要header按时间升序显示。

2005 spring
2005 fall
2007 summer

我在这里使用了代码:

- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
{
    [self.sectionKeys sortUsingSelector:@selector(localizedCaseInsensitiveCompare:)];
    NSString *key = [self.sectionKeys objectAtIndex:section];
    return key;
}

year 配合使用效果很好。但是,由于字母原因,fall 出现在 springsummer 之前,请问如何解决?

所以你有一个带有节键的数组。但是sections不是按照数组的顺序排列的,需要排序。您会注意到 cellForRowAtIndexPath: 需要完全相同的信息。所以在这个地方排序是错误的。

我如何处理这个问题:我有一个 属性 "unsortedSectionKeys" 和一个 属性 "sortedSectionKeys"。 sortedSectionKeys 有一个 getter 检查 nil 并存储 unsortedSectionKeys 的排序副本,如果它是 nil。每当 unsortedSectionKeys 发生变化时,您只需将 sortedSectionKeys 设置为 nil。 (这至少解决了一些问题)。

对于排序,您需要编写正确的代码。使用 (void)sortUsingComparator:(NSComparator)cmptr 对可变对象进行排序,或 - (NSArray *)sortedArrayUsingComparator:(NSComparator)cmptr 获取数组的排序副本。

示例:

[self.sectionKeys sortArrayUsingComparator:^NSComparisonResult(NSString* obj1, NSString* obj2) {
    NSInteger year1 = obj1.integerValue;
    NSInteger year2 = obj2.integerValue;
    if (year1 < year2) return NSOrderedAscending;
    if (year1 > year2) return NSOrderedDescending;

    NSInteger season1 = 0;
    if ([obj1 rangeOfString:@"spring" options:NSCaseInsensitiveSearch].location != NSNotFound)
        season1 = 1;
    if ([obj1 rangeOfString:@"summer" options:NSCaseInsensitiveSearch].location != NSNotFound)
        season1 = 2;
    if ([obj1 rangeOfString:@"fall" options:NSCaseInsensitiveSearch].location != NSNotFound)
        season1 = 3;
    if ([obj1 rangeOfString:@"winter" options:NSCaseInsensitiveSearch].location != NSNotFound)
        season1 = 4;

    NSInteger season2 = 0;
    if ([obj2 rangeOfString:@"spring" options:NSCaseInsensitiveSearch].location != NSNotFound)
        season2 = 1;
    if ([obj2 rangeOfString:@"summer" options:NSCaseInsensitiveSearch].location != NSNotFound)
        season2 = 2;
    if ([obj2 rangeOfString:@"fall" options:NSCaseInsensitiveSearch].location != NSNotFound)
        season2 = 3;
    if ([obj2 rangeOfString:@"winter" options:NSCaseInsensitiveSearch].location != NSNotFound)
        season2 = 4;

    if (season1 < season2) return NSOrderedAscending;
    if (season1 > season2) return NSOrderedDescending;
    return NSOrderedSame;
}];

您决定冬天是一年中的第一个还是最后一个季节,因为通常是 12 月到 2 月。

使用自定义比较器获取自定义排序顺序:

NSMutableArray *array = [@[ @"2005 fall", @"2005 spring", @"2007 summer" ] mutableCopy];

NSArray *seasons = @[ @"spring", @"summer", @"fall", @"winter" ];

[array sortUsingComparator:^NSComparisonResult(NSString *str1, NSString *str2) {
    NSArray *parts1 = [str1 componentsSeparatedByString:@" "];
    NSArray *parts2 = [str1 componentsSeparatedByString:@" "];

    NSString *year1 = parts1[0];
    NSString *year2 = parts2[0];
    NSComparisonResult yearRes = [year1 compare:year2 options:NSNumericSearch];
    if (yearRes == NSOrderedSame) {
        NSString *season1 = parts1[1];
        NSString *season2 = parts2[1];

        NSUInteger index1 = [seasons indexOfObject:season1];
        NSUInteger index2 = [seasons indexOfObject:season2];

        if (index1 < index2) {
            return NSOrderedAscending;
        } else if (index1 > index2) {
            return NSOrderedDescending;
        } else {
            return NSOrderedSame;
        }
    } else {
        return yearRes;
    }
}];

注意 - 我可能把 NSOrderedAscendingNSOrderedDescending 倒过来了。如果同年季节的排序顺序相反,则交换它们。

您需要一种查找机制来定义季节的顺序

NSArray *seasons = @[@"spring", @"summer", @"fall", @"winter"];

NSArray *strings = @[@"2005 fall",@"2007 spring",  @"2005 spring", @"2007 winter", @"2005 winter"];
strings = [strings sortedArrayUsingComparator:^NSComparisonResult(NSString *obj1, NSString *obj2) {
    NSArray *string1Comps = [obj1 componentsSeparatedByString:@" "];
    NSArray *string2Comps = [obj2 componentsSeparatedByString:@" "];

    NSComparisonResult compareYearResult = [@([string1Comps[0] integerValue]) compare:@([string2Comps[0] integerValue]) ];
    if (compareYearResult == NSOrderedSame) {
        return [@([seasons indexOfObject:string1Comps[1]]) compare:@([seasons indexOfObject:string2Comps[1]])];
    }
    return compareYearResult;
}];

结果

(
    2005 spring,
    2005 fall,
    2005 winter,
    2007 spring,
    2007 winter
)

另一种查找机制可以是块

NSNumber* (^lookUpSeason)(NSString *) = ^(NSString *seasonname){
    static NSArray *seasons;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        seasons = @[@"spring", @"summer", @"fall", @"winter"];
    });
    return @([seasons indexOfObject:seasonname]);
};

乍一看可能有点笨重,但使用后可读性提高。

return [@([seasons indexOfObject:string1Comps[1]]) compare:@([seasons indexOfObject:string2Comps[1]])];

变成

return [lookUpSeason(string1Comps[1]) compare:lookUpSeason(string2Comps[1])];

在这两种情况下,您还可以将查找代码放入比较器块中,这将使您有机会在其他地方删除与查找相同的比较器。

赞:

NSArray *strings = @[@"2005 fall", @"2007 spring",  @"2005 spring", @"2007 winter", @"2005 winter", @"2005 summer", @"2000 hhh"];

NSComparisonResult (^yearAndSeasonComparator)(id,id) = ^NSComparisonResult(NSString *obj1, NSString *obj2) {
    NSNumber* (^lookUpSeason)(NSString *) = ^(NSString *seasonname){
        static NSArray *seasons;
        static dispatch_once_t onceToken;
        dispatch_once(&onceToken, ^{
            seasons = @[@"spring", @"summer", @"fall", @"winter"];
        });
        return @([seasons indexOfObject:seasonname]);
    };

    NSArray *string1Comps = [obj1 componentsSeparatedByString:@" "];
    NSArray *string2Comps = [obj2 componentsSeparatedByString:@" "];

    NSComparisonResult compareYearResult = [@([string1Comps[0] integerValue]) compare:@([string2Comps[0] integerValue]) ];
    if (compareYearResult == NSOrderedSame) {
        return [lookUpSeason(string1Comps[1]) compare:lookUpSeason(string2Comps[1])];
    }
    return compareYearResult;
};

strings = [strings sortedArrayUsingComparator:yearAndSeasonComparator];

分配给 yearAndSeasonComparator 的块现在可以在对类似字符串进行排序的其他地方重复使用。