0

次のコードで降順ソートが機能しない理由について、私は頭を悩ませています。トップ 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?
}
4

2 に答える 2

1

ヘルパー機能

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:<mode> ]ください。メソッドに1つのことだけを実行させる方がよいでしょう。

于 2012-12-30T11:58:28.470 に答える
0

並べ替えへの 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;
    }
}
于 2012-12-30T07:20:24.357 に答える