【问题标题】:Convert days represented in flags enum to human readable days将标志枚举中表示的天数转换为人类可读的天数
【发布时间】:2012-05-29 17:04:06
【问题描述】:
// Values of the individual days as powers of two
enum {
    kMonday = 64,
    kTuesday = 32,
    kWednesday = 16,
    kThursday = 8,
    kFriday = 4,
    kSaturday = 2,
    kSunday = 1,
};

将所有 127 天的变体转换为人类可读字符串的最快方法是什么。

例如,如果我得到数字 7,我想输出“Fri-Sunday”

如果我得到数字 66,我想输出“周一,周六”

【问题讨论】:

    标签: objective-c date enums


    【解决方案1】:

    基本上你有两个选择:

    • 创建一个工厂,您将合并天数的整数交给您,然后您将取回字符串

    • 创建包装器对象,包装 int 并提供访问内部逻辑的方法

    我写了一个包装器:

    #import <Foundation/Foundation.h>
    
    typedef NS_OPTIONS(NSUInteger, WeekDays) {
        kMonday     = 1 << 6,
        kTuesday    = 1 << 5,
        kWednesday  = 1 << 4,
        kThursday   = 1 << 3,
        kFriday     = 1 << 2,
        kSaturday   = 1 << 1,
        kSunday     = 1 << 0
    };
    
    @interface DaysWrapper : NSObject
    -(id)initWithDays:(WeekDays)weekDays;
    @end
    
    @interface DaysWrapper ()
    @property (nonatomic,retain) NSMutableArray *days;
    @end
    
    
    @implementation DaysWrapper{
        int internalDays;
    }
    
    +(instancetype)dayWrapperWithDayBitmask:(WeekDays)daybits
    {
        return [[DaysWrapper alloc] initWithDays:daybits];
    }
    
    -(instancetype)initWithDays:(WeekDays)weekDays
    {
        if (self = [super init]) {
            WeekDays wholeWeek = 127;
            internalDays = weekDays & wholeWeek;
            _days = [@[] mutableCopy];
    
            while (wholeWeek) {
                wholeWeek >>= 1;
                if (weekDays & (wholeWeek +1)) {
                    [_days addObject:[NSNumber numberWithBool:YES]];
                } else {
                    [_days addObject:[NSNumber numberWithBool:NO]];
                }
            }
        }
        return self;
    }
    
    -(NSString *)description
    {
        static dispatch_once_t onceToken;
        static NSArray *dayNames;
        static NSDictionary *fullnamesForDayNames;
        dispatch_once(&onceToken, ^{
            dayNames = @[@"Mon", @"Tues", @"Wend",@"Thu", @"Fri",@"Sat", @"Sun"];
            fullnamesForDayNames = [[NSDictionary alloc] initWithObjects: @[@"Monday",@"Tuesday",@"Wendsday",@"Thursday",@"Friday",@"Saturday",@"Sunday"]
                                                                 forKeys:dayNames];
        });
    
    
        NSMutableString *returnSting = [@"" mutableCopy];
        __block BOOL previousWasAvailable = NO;
        NSMutableArray *dayRanges = [@[] mutableCopy];
        [self.days enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
            if (!previousWasAvailable && [obj boolValue])
                [dayRanges addObject:[@[] mutableCopy]];
    
            if ([obj boolValue]) {
                NSMutableArray *actualRange = [dayRanges lastObject];
                [actualRange addObject:dayNames[idx]];
            }
            previousWasAvailable = [obj boolValue];
        }];
    
        [dayRanges enumerateObjectsUsingBlock:^(NSMutableArray *rangeArray, NSUInteger idx, BOOL *stop) {
    
            if ([returnSting length]){
                [returnSting appendString:@","];
            }
    
            if ([rangeArray count] > 1) {
                [returnSting appendString: [rangeArray firstObject]];
    
                if ([rangeArray count] > 2){
                    [returnSting appendString:@"-"];
                } else {
                    [returnSting appendString:@","];
                }
            }
    
            if (idx == [dayRanges count]-1){
                [returnSting appendString: fullnamesForDayNames[[rangeArray lastObject]]];
            } else {
                [returnSting appendString:[rangeArray lastObject]];
            }
        }];
    
        return returnSting;
    }
    
    @end
    
    int main(int argc, const char * argv[])
    {
        @autoreleasepool {
    
            WeekDays monAndFriday    = kMonday | kFriday;
            WeekDays thurToSat       = kThursday | kFriday | kSaturday;
            WeekDays weekEnd         = kFriday | kSaturday | kSunday;
            WeekDays mondAndWeekend  = weekEnd | kMonday;
            WeekDays friSat          = kFriday | kSaturday;
            WeekDays everySecondDay  = 8 | 32 | 2;
            WeekDays moday           = kMonday;
            WeekDays workWeek        = kMonday | kTuesday | kWednesday | kThursday | kFriday;
            WeekDays wholeWeek       = workWeek | weekEnd;
            WeekDays notThursday     =  ~kThursday & wholeWeek;
    
            NSLog(@"%@", [DaysWrapper dayWrapperWithDayBitmask:monAndFriday]);
            NSLog(@"%@", [DaysWrapper dayWrapperWithDayBitmask:weekEnd]);
            NSLog(@"%@", [DaysWrapper dayWrapperWithDayBitmask:thurToSat]);
            NSLog(@"%@", [DaysWrapper dayWrapperWithDayBitmask:mondAndWeekend]);
            NSLog(@"%@", [DaysWrapper dayWrapperWithDayBitmask:friSat]);
            NSLog(@"%@", [DaysWrapper dayWrapperWithDayBitmask:everySecondDay]);
            NSLog(@"%@", [DaysWrapper dayWrapperWithDayBitmask:moday]);
            NSLog(@"%@", [DaysWrapper dayWrapperWithDayBitmask:workWeek]);
            NSLog(@"%@", [DaysWrapper dayWrapperWithDayBitmask:wholeWeek]);
            NSLog(@"%@", [DaysWrapper dayWrapperWithDayBitmask:notThursday]);
        }
        return 0;
    }
    

    输出

    Mon,Friday
    Fri-Sunday
    Thu-Saturday
    Mon,Fri-Sunday
    Fri,Saturday
    Tues,Thu,Saturday
    Monday
    Mon-Friday
    Mon-Sunday
    Mon-Wend,Fri-Sunday
    

    随机想法

    • 不必在数组名称 self.days 中保存整数信息的副本,而是可以在每次需要时动态处理它以减少空间
    • 工厂的逻辑基本相同

    常规代码大修(ARC、现代 obj-c 语法、NS_OPTIONS、...)2015 年 5 月 21 日

    【讨论】:

    • 请注意,通过将接下来几天的范围分组到数组中,而不是处理这些数组,我能够大大简化描述方法。
    • 请注意,我更改了代码以写出最后一天的名称,正如您在帖子中显示的那样。
    【解决方案2】:

    这是一个有趣的挑战。

    #import <Foundation/Foundation.h>
    enum {
        kMonday = 1 << 0,
        kTuesday = 1 << 1,
        kWednesday = 1 << 2,
        kThursday = 1 << 3,
        kFriday = 1 << 4,
        kSaturday = 1 << 5,
        kSunday = 1 << 6,
    };
    typedef int DayBits;
    
    NSString * const shortDayNames[] = { @"Mon", @"Tues", @"Wed", @"Thurs", @"Fri", @"Sat", @"Sun" };
    NSString * const fullDayNames[] = { @"Monday", @"Tuesday", @"Wednesday", @"Thursday", @"Friday", @"Saturday", @"Sunday" };
    
    
    int main(int argc, const char * argv[])
    {
    
        @autoreleasepool {
            // Demo all possible combinations
            for( DayBits days_as_bits = 0; days_as_bits < 128; days_as_bits++ ){
                // Create an index set from the bits
                NSMutableIndexSet * indexes = [NSMutableIndexSet indexSet];
                for( int bit = 0; bit < 7; bit++ ){
                    if( days_as_bits & (1 << bit) ){
                        [indexes addIndex:bit];
                    }
                }
    
                // Create string for result
                NSMutableString * daysDesc = [NSMutableString string];
                // Enumerate the index set backwards and build up the string
                __block BOOL contiguous = NO;
                [indexes enumerateIndexesWithOptions:NSEnumerationReverse 
                                          usingBlock:^(NSUInteger idx, BOOL *stop) {
                    // Use short names unless this is the name that will appear 
                    // at the end of the string
                    NSString * const * dayNames = shortDayNames;
                    if (0 == [daysDesc length]) {
                        dayNames = fullDayNames;
                    }
                    // If the previous index is present, we're working on a contiguous set
                    if( [indexes containsIndex:(idx - 1)] ){
                        // If we were already in a contiguous set, just continue
                        if( contiguous ){
                            return;
                        }
                        // This is the end day of a contiguous set; place the name 
                        // and a hyphen
                        else {
                            [daysDesc insertString:[NSString stringWithFormat:@"-%@", dayNames[idx]]
                                                                      atIndex:0];
                            contiguous = YES;
                            return;
                        }
                    }
                    // We've reached the start day of a set. 
                    // Turn off contiguous and fall through
                    else {
                        contiguous = NO;
                    }
    
                    // Place a comma and today's name
                    [daysDesc insertString:[NSString stringWithFormat:@", %@", dayNames[idx]]
                                                              atIndex:0];
                }];
                // Clean up extraneous comma and space at the beginning of the string
                daysDesc = [daysDesc stringByTrimmingCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:@" ,"]];
                NSLog(@"%d: %@", days_as_bits, daysDesc);
            }
    
        }
        return 0;
    }
    

    请注意,我切换了您的 enum 以使其正常工作,因此这实际上对您来说可能完全没用,但希望对您有所帮助。这意味着,例如,7 是 kMonday | kTuesday | kWednesday 而不是 kFriday | kSaturday | kSunday,所以结果是 Mon-Wed

    我认为索引集的使用可能是我必须提供的主要见解。

    您也许可以通过一些工作来切换事物(取消反转枚举等);我已经浪费了足够多的时间了^W^W^W满足了我对此的好奇。

    【讨论】:

    • 也应该考虑 NSIndexSet
    • 如果索引集能给你更多的查询方式就更好了。我开始使用它是因为我希望找到一种方法来一次获得所有连续范围(description 存储/显示它们的方式),但最终这与迭代位本身基本相同。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-01-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多