【问题标题】:NSUSerDefaults with NSMutableArray sort by desc orderNSUSerDefaults 和 NSMutableArray 按 desc 顺序排序
【发布时间】:2012-12-14 20:45:05
【问题描述】:

我对为什么降序排序不适用于以下代码感到头疼。我想限制前 5 名的分数和其他逻辑。分数如下所示:22/30、12/18、34/38、23/32 等。我添加/删除了 SortDescriptor 以按降序排序,它似乎适用于前 3 个项目,但随后无法正确排序.有人可以帮忙吗?

- (NSMutableArray*) method1:(NSString *) mode byScore: (NSString *) score
{
    NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
    NSMutableArray *array = [[defaults objectForKey:mode]mutableCopy];

    if (!array)
    {
        array = [[NSMutableArray alloc] init];
    }
    NSLog(@"The content of array is%@", array);

    if ([array count] < 5)
    {
      if (![array containsObject:score])
      {
          [array addObject:score];
          // Need to sort here. But not too sure this is the right place
          NSLog(@"The content of the sorted array upto 5 is%@", array); 
      }
    }
    else
    {
       if (![array containsObject:score])
       {
           if ([array lastObject] < score)
           {
               [array addObject:score];
               // Need to sort here before I remove the last object                   
               [array removeLastObject];
               NSLog(@"The content of the sorted array else is%@",array);
           }
       }
    }
    [defaults setObject:array forKey:mode];
    [defaults synchronize];
    // I want the array in NSUserDefaults to be sorted in desc order
    // don't know what to return here ==> the array object or the defaults object cast    to NSMutableArray?
}

【问题讨论】:

  • 是排序的代码吗?
  • 绝对不返回“转换为 NSMutableArray 的默认对象”。返回array 是有道理的,但是您不确定应该返回什么这一事实表明您可能根本不需要返回任何东西,并且返回类型应该是void
  • 我更新了我的问题。我正在使用:NSSortDescriptor 类按降序排序,但没有用

标签: objective-c ios


【解决方案1】:

一种对array进行排序的方法:

首先定义一个块getNumeratorAndDenominatorFromScoreString如下:

BOOL (^getNumeratorAndDenominatorFromScoreString)(NSString *, NSInteger *, NSInteger *) = ^(NSString *scoreString, NSInteger *numeratorOut, NSInteger *denominatorOut) {
    BOOL res = NO;
    NSArray *components = [scoreString componentsSeparatedByString:@"/"];
    if (components && 
        [components count] == 2) {
        res = YES;
        if (numeratorOut) {
            NSNumber *numeratorNumber = [components objectAtIndex:0];
            *numeratorOut = [numeratorNumber integerValue];
        }
        if (denominatorOut) {
            NSNumber *denominatorNumber = [components objectAtIndex:1];
            *denominatorOut = [denominatorNumber integerValue];
        }
    }
    return res;
};

然后将此块与-[NSArray sortedArrayUsingComparator]一起使用对array进行排序:

NSArray *sortedArray = [array sortedArrayUsingComparator: ^(id obj1, id obj2) {
    NSComparisonResult res = NSOrderedSame;

    NSString *score1 = (NSString *)obj1;
    NSString *score2 = (NSString *)obj2;

    NSInteger numerator1, denominator1, numerator2, denominator2;
    BOOL res1, res2;

    res1 = getNumeratorAndDenominatorFromScoreString(score1, &numerator1, &denominator1);
    res2 = getNumeratorAndDenominatorFromScoreString(score2, &numerator2, &denominator2);

    if (res1
        && res2) {
        CGFloat value1 = ((CGFloat)numerator1)/((CGFloat)denominator1);
        CGFloat value2 = ((CGFloat)numerator2)/((CGFloat)denominator2);

        if (value1 > value2) {
            res = NSOrderedDescending;
        } else if (value1 < value2) {
            res = NSOrderedAscending;
        }
    }
    return res;
}];

这会将array 从小到大排序。要从大到小排序,只需替换

if (value1 > value2) {
    res = NSOrderedDescending;
} else if (value1 < value2) {
    res = NSOrderedAscending;
}

if (value1 > value2) {
    res = NSOrderedAscending;
} else if (value1 < value2) {
    res = NSOrderedDescending;
}

这种方法的可读结构是,[大部分不是]伪代码

- (void)addScoreToHighscores:(NSString *)score withMethod:(NSString *)mode
{
    NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];

    NSArray *currentHighscores = [defaults arrayForKey:mode];
    if (!currentHighscores) currentHighscores = [NSArray array];

    if (![currentHighscores containsObject:score]) {
        currentHighscores = [currentHighscores arrayByAddingObject:score];

        //sort currentHighscores: adapt the above code so that we have
        BOOL (^getNumeratorAndDenominatorFromScoreString)(NSString *, NSInteger *, NSInteger *) = //as above
        NSArray *newHighscores = [currentHighscores sortedArrayUsingComparator:^(id obj1, id obj2) {
            //as above
        }];

        //truncate newHighscores
        if ([newHighscores count] > 5) {
            newHighscores = [newHighscores subarrayWithRange:NSMakeRange(0,5)];
        }

        [defaults setObject:newHighscores forKey:mode];
    } else {
        //since score is already in currentHighscores, we're done.
        return;
    }
}

如果您需要筛选出不相等的分数但分数相等的分数(@“1/2”和@“5/10”),则需要更多聪明。


这是上面勾勒的完整代码:

- (void)addScoreToHighscores:(NSString *)score withMethod:(NSString *)mode
{
    NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];

    NSArray *currentHighscores = [defaults arrayForKey:mode];
    if (!currentHighscores) currentHighscores = [NSArray array];

    if (![currentHighscores containsObject:score]) {
        currentHighscores = [currentHighscores arrayByAddingObject:score];

        //sort currentHighscores: adapt the above code so that we have
        BOOL (^getNumeratorAndDenominatorFromScoreString)(NSString *, NSInteger *, NSInteger *) = ^(NSString *scoreString, NSInteger *numeratorOut, NSInteger *denominatorOut) {
            BOOL res = NO;
            NSArray *components = [scoreString componentsSeparatedByString:@"/"];
            if (components && 
                [components count] == 2) {
                res = YES;
                if (numeratorOut) {
                    NSNumber *numeratorNumber = [components objectAtIndex:0];
                    *numeratorOut = [numeratorNumber integerValue];
                }
                if (denominatorOut) {
                    NSNumber *denominatorNumber = [components objectAtIndex:1];
                    *denominatorOut = [denominatorNumber integerValue];
                }
            }
            return res;
        };

        NSArray *newHighscores = [currentHighscores sortedArrayUsingComparator:^(id obj1, id obj2) {
            NSComparisonResult res = NSOrderedSame;

            NSString *score1 = (NSString *)obj1;
            NSString *score2 = (NSString *)obj2;

            NSInteger numerator1, denominator1, numerator2, denominator2;
            BOOL res1, res2;

            res1 = getNumeratorAndDenominatorFromScoreString(score1, &numerator1, &denominator1);
            res2 = getNumeratorAndDenominatorFromScoreString(score2, &numerator2, &denominator2);

            if (res1
                && res2) {
                CGFloat value1 = ((CGFloat)numerator1)/((CGFloat)denominator1);
                CGFloat value2 = ((CGFloat)numerator2)/((CGFloat)denominator2);

                if (value1 > value2) {
                    res = NSOrderedDescending;
                } else if (value1 < value2) {
                    res = NSOrderedAscending;
                }
            }
            return res;
        }];

        //truncate newHighscores
        if ([newHighscores count] > 5) {
            newHighscores = [newHighscores subarrayWithRange:NSMakeRange(0,5)];
        }

        [defaults setObject:newHighscores forKey:mode];
    } else {
        //since score is already in currentHighscores, we're done.
        return;
    }
}

【讨论】:

  • 我认为这个解决方案可能更适合我,除了我已经压缩了代码。正如 Nate Chandler 提到的,currentHighscores = [currentHighscores arrayByAddingObject:score];没有做任何事情。请帮忙
  • 在最新的编辑中,我为上面勾勒的方法 -addScoreToHighscores:withMethod: 添加了完整代码。
  • 可以进行的改进是向NSArray 添加一个类别方法,命名为-pfx_containsFractionStringWithFloatValueEqualToFloatValueForFractionString:(将pfx 替换为您的项目前缀),这将返回YES for @" 1/2" 不仅如果@"1/2"currentHighscores 中,而且如果@"2/4"@"9/18" 等在currentHighscores 中。然后if (![currentHighscores containsObject:score]) { 行将替换为if (![currentHighscores pfx_containsFractionStringWithFloatValueEqualToFloatValueForFractionString:score]) {
  • 优秀。创造奇迹!由于我还不熟悉块,我已经合并了代码。无论如何,谢谢!
  • 只是一个小改动。我保留了与相同的现有分数匹配的仍然可以降低的分数。例如,如果我有 1/2 的高分,当我得到 11/22、2/4、9/18 等时,我会接受一切,因为我认为这些是不同的分数。但是,当我得到相同的分数(9/18、1/2、11/22、2/4 等)时,我会忽略它们
【解决方案2】:

辅助函数

static NSComparisonResult CompareFloats( float a, float b )
{
    if ( a < b ) { return NSOrderedAscending ; }
    else if ( a > b ) { return NSOrderedDescending ; }
    return NSOrderedSame ;
}

NSString 上的类别

@implementation NSString (Stuff)

-(float)floatValueForFraction
{
    NSArray * components = [ self componentsSeparatedByString:@"/" ] ;
    return [ components[0] floatValue ] / [ components[1] floatValue ] ;
}

@end

你的方法:

- (void)addScore:(NSString*)score forMode:(NSString*)mode
{
    NSUserDefaults * defaults = [ NSUserDefaults standardUserDefaults ] ;
    NSArray * scores = [ defaults objectForKey:mode ] ;

    scores = scores ? [ scores arrayByAddingObject:score ] : @[ score ] ;
    scores = [ scores sortedArrayUsingComparator:^(NSString * a, NSString * b){
        return CompareFloats( [ a floatValueForFraction ], [ b floatValueForFraction ] ) ;
    }]

    if ( scores.count > 5 ) { scores = [ scores subarrayWithRange:(NSRange){ .length = 5 } ] ; }

    [ default setObject:scores forKey:mode ] ;
}

如果你想要调用这个方法后更新的高分,使用[ [ NSUserDefaults standardUserDefaults ] objectForKey:&lt;mode&gt; ]即可。最好让你的方法只做一件事。

【讨论】:

  • 这更短,但 Nate Chandler 的回答更可靠。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-01-13
  • 1970-01-01
  • 2021-10-07
  • 2014-07-11
  • 2020-09-12
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多